为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

4-Linux 内核C语言的特点

2012-04-29 30页 ppt 723KB 26阅读

用户头像

is_716011

暂无简介

举报
4-Linux 内核C语言的特点nullLinux 内核C语言的特点Linux 内核C语言的特点nullGNU对C语言的扩展 Linux内核程序的特点语句表达式语句表达式GNU C 把包含在括号中的复合语句看做是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方,你可以在语句表达式中使用循环、局部变量等。 include/linux/kernel.h 159: #define min_t(type,x,y) \ 160: ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) 这里定义...
4-Linux 内核C语言的特点
nullLinux 内核C语言的特点Linux 内核C语言的特点nullGNU对C语言的扩展 Linux内核程序的特点语句表达式语句表达式GNU C 把包含在括号中的复合语句看做是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方,你可以在语句表达式中使用循环、局部变量等。 include/linux/kernel.h 159: #define min_t(type,x,y) \ 160: ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) 这里定义了一个安全的求最小值的宏 语句表达式语句表达式在标准 C 中,通常定义为: #define min(x,y) ((x) < (y) ? (x) : (y)) 这个定义计算 x 和 y 分别两次,当参数有副作用时,将产生不正确的结果 使用语句表达式只计算参数一次,避免了可能的错误。 语句表达式通常用于宏定义。 TypeofTypeof使用前一节定义的宏需要知道参数的类型,利用 typeof 可以定义更通用的宏,不必事先知道参数的类型 include/linux/kernel.h 141: #define min(x,y) ({ \ 142: const typeof(x) _x = (x); \ 143: const typeof(y) _y = (y); \ 144: (void) (&_x == &_y); \ 145: _x < _y ? _x : _y; }) TypeofTypeof(void) (&_x == &_y)这句话本身都执行程序来讲完全是一句废话 它的作用在于,本身我们无法做这样的操作typeof(_x)==typeof(_y),所以故意判断他们2个的地址指针是否相等,显然是不可能相等, 但是如果_x和_y的类型不一样,其指针类型也会不一样,2个不一样的指针类型进行比较操作,会抛出一个编译警告。 比如:char *p; int *q; 然后p==q;,这个判断因为一个是char*一个是int*,会在编译时产生一个warning零长度数组零长度数组GNU C 允许使用零长度数组 在定义变长对象的头结构时,这个特性非常有用。结构的最后一个元素定义为零长度数组,它不占结构的空间。 在标准 C 中则需要定义数组长度为 1,分配时计算对象大小比较复杂。 struct { int length; char content[0]; }; 零长度数组零长度数组例子:/usr/include/linux/if_pppox.h struct pppoe_tag {     __u16 tag_type;     __u16 tag_len;     char tag_data[0]; } __attribute ((packed)); 零长度数组零长度数组使用起来非常方便,创建时,malloc一段结构体大小加上可变长数据长度的空间给它,可变长部分可按数组的方式访问 struct pppoe_tag *sample_tag; __u16 sample_tag_len = 10; sample_tag = (struct pppoe_tag *)malloc(sizeof(struct pppoe_tag)+sizeof(char)*sample_tag_len); sample_tag->tag_type = 0xffff; sample_tag->tag_len = sample_tag_len; sample_tag->tag_data[0]=....   ... 零长度数组零长度数组释放时,直接把整个结构体free掉就可以了 free(sample_tag) 可变参数宏可变参数宏在 GNU C 中,宏可以接受可变数目的参数,就象函数一样 例如 include/linux/kernel.h 110: #define pr_debug(fmt,arg...) \ printk(KERN_DEBUG fmt,##arg) arg 表示其余的参数,可以是零个或多个,这些参数以及参数之间的逗号构成 arg 的值,在宏扩展时替换 arg 可变参数宏可变参数宏pr_debug("%s:%d",filename,line)扩展为 printk("<7>" "%s:%d", filename, line) pr_debug("success!\n“)扩展为 printk("<7>" "success!\n") 标号元素标号元素标准 C 要求数组或结构变量的初使化值必须以固定的顺序出现 在 GNU C 中,通过指定索引或结构域名,允许初始化值以任意顺序出现。 指定数组索引的方法是在初始化值前写 '[INDEX] =',要指定一个范围使用 '[FIRST ... LAST] =' 的形式标号元素标号元素fs/ext2/file.c 41: struct file_operations ext2_file_operations = { 42: llseek: generic_file_llseek, 43: read: generic_file_read, 44: write: generic_file_write, 45: ioctl: ext2_ioctl, 46: mmap: generic_file_mmap, 47: open: generic_file_open, 48: release: ext2_release_file, 49: fsync: ext2_sync_file, 50 };case范围case范围GNU C 允许在一个 case 标号中指定一个连续范围的值,例如: arch/i386/kernel/irq.c 1062: case '0' ... '9': c -= '0'; break; 1063: case 'a' ... 'f': c -= 'a'-10; break; 1064: case 'A' ... 'F': c -= 'A'-10; break; case '0' ... '9': 相当于 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': 声明属性声明属性GNU C 允许声明函数、变量和类型的特殊属性,以便手工的代码优化和更仔细的代码检查。 要指定一个声明的属性,在声明后写 __attribute__ (( ATTRIBUTE )) 其中 ATTRIBUTE 是属性说明,多个属性以逗号分隔。 noreturn属性 用于函数,表示该函数从不返回。这可以让编译器生成稍微优化的代码,最重要的是可以消除不必要的警告信息比如未初使化的变量。 声明属性声明属性* unused用于函数和变量,表示该函数或变量可能不使用,这个属性可以避免编译器产生警告信息。 * section (“section-name“) 属性 section 用于函数和变量,通常编译器将函数放在 .text 节,变量放在.data 或 .bss 节,使用 section 属性,可以让编译器将函数或变量放在指定的 节中。 声明属性声明属性include/linux/init.h 78: #define __init __attribute__ ((__section__ (".text.init"))) 79: #define __exit __attribute__ ((unused, __section__(".text.exit"))) 声明属性声明属性* aligned (ALIGNMENT) 属性 aligned 用于变量、结构或联合类型,指定变量、结构域、结构或联合的对齐量,以字节为单位,例如: ++++ include/asm-i386/processor.h 294: struct i387_fxsave_struct { 295: unsigned short cwd; 296: unsigned short swd; 297: unsigned short twd; 298: unsigned short fop; 299: long fip; 300: long fcs; 301: long foo; ...... 308: } __attribute__ ((aligned (16))); 声明属性声明属性* packed 属性 packed 用于变量和类型,用于变量或结构域时表示使用最小可能的对齐,用于枚举、结构或联合类型时表示该类型使用最小的内存。例如: ++++ include/asm-i386/desc.h 51: struct Xgt_desc_struct { 52: unsigned short size; 53: unsigned long address __attribute__((packed)); 54: }; 域 address 将紧接着 size 分配。属性 packed 的用途大多是定义硬件相关的结构,使元素之间没有因对齐而造成的空洞。 位运算位运算位运算符C语言提供了六种位运算符:   &   按位与   |   按位或   ^  按位异或   ~  取反   << 左移   >> 右移 位运算例子位运算例子设备号运算 MAJOR,MINOR,mk_dev() do … while(0)do … while(0)空语句在编译时候会出现警告,所以有必要用#define FOO do { } while(0). 这样做是为了能够在里面定义局部变量 这样做是为了能够在条件语句中使用复杂的宏定义 do … while(0)do … while(0)#define foo(x) \ action1(); \ action2() 在以下情况下: if(NULL == pPointer)    foo(); 就会出现action1和action2不会同时被执行的情况,而这显然不是程序设计的目的。 do … while(0)do … while(0)以上的第3种情况用单独的{}也可以实现,但是为什么一定要一个do{}while(0)呢,看以下代码: #define switch(x,y) { int tmp; tmp="x"; x=y; y=tmp; } if(x>y) switch(x,y); else       //error, parse error before else otheraction(); 在把宏引入代码中,会多出一个分号,从而会报错。 do … while(0)do … while(0)do...while(0)消除goto语句。 通常,如果在一个函数中开始要分配一些资源,然后在中途执行过程中如果遇到错误则退出函数,当然,退出前先释放资源Container_ofContainer_ofcontainer_of在Linux Kernel中的应用非常广泛,它用于获得某结构中某成员的入口地址. Kernel.h 定义 指针ptr指向结构体type中的成员member;通过指针ptr,返回结构体type的起始地址。null#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) ((size_t) &((TYPE *)0)->MEMBER)把0地址转化为TYPE结构的指针, 然后获取该结构中MEMBER成员的指针,并将其强制转换为size_t类型。 于是,由于结构从0地址开始定义,因此,这样求出的MEMBER成员地址,实际上就是它在结构中的偏移量。nullgoto语句的使用 错误处理,释放资源null
/
本文档为【4-Linux 内核C语言的特点】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索