GNU C与ANSI C
来源:互联网 发布:新疆陌陌网络 编辑:程序博客网 时间:2024/06/01 10:24
1、零长度数组
GNU C允许使用零长度数组,在定义变长对象的头结构时,这个特性特别有用。例如:
struct var_data
{
int len;
char data[0];
};
char data[0]仅仅意味着程序中通过var_data结构实例的data[index]成员可以访问len之后的第index个地址,它并没有为data[]数组分配内存,因此sizeof(struct var_data)=sizeof(int).
假设struct var_data的数据域保存在struct var_data紧接着的内存区域,通过如下代码可以遍历这些数据:
struct var_data s;
...
for(i = 0;i < s.len;i++)
{
printf("x",s.data[i]);
}
2.case 范围
GNU C支持case x...y这样的语法,区间[x,y]的数都会满足这个case的条件,请看下面的代码:
switch(ch)
{
case '0'...'9':c -= '0';
break;
case 'a'...'f':c -= 'a';
break;
}
代码中的case '0'...'9'等价于标准C中的如下代码:
case '0':
case '1':
...
case '9':
3.语句表达式
GNU C把包含在括号中的复合语句看做是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方。我们可以在语句表达式中使用原本只能在复合语句中使用的循环变量、局部变量等,例如:
#define min_t(type,x,y) \
({ type __x = (x);type __y = (y); __x < __y ? __x : __y;})
int ia,ib,mini;
float fa,fb,minf;
mini = min_t(int ,ia ,ib);
minf = mini_t(float ,ia, ib);
因为重新定义了__x,__y这两个局部变量,所以以上述方式定义的宏将不会产生副作用。在标C中,对应的如下宏则会产生副作用:
#define min(x,y) ((x)<(y)?(x):(y))
代码min(++ia,++ib)会被展开为((++ia) < (++ib)?:(++ia):(++ib)),传入的宏的参数被增加了两次。
4、typeof关键字
typeof(x)语句可以获得x的类型,因此,我们可以借助typedef重新定义min这个宏:
#define min(x,y)\
(const typeof(x) __x = (x); \
(const typeof(y) __y = (y); \
(void)(&__x == &__y);
__x < __y ? __x :__y;})
我们不需要像min_t(type,x,y)这个宏那样把type传入,因为通过关键字就可以获得type。代码行 (void)(&__x == &__y);作用是检查__x,__y类型是否一致!
5、可变参数的宏
标C只支持可变参数的函数,意味着函数的参数是不固定的,例如printf()函数原型:
int printf( const char *format[,argument]...);
而在GNU C中,宏也可以接受可变数目的参数,例如:
#define pr_debug(fmt,arg...) \
printk(fmt,##arg)
这里的arg表示其余的参数可以是零个或多个,这些参数以及参数之间的逗号构成arg的值,在宏扩展时替换arg,例如下列代码:
pr_debug("%s:%d",filename,line)
会被扩展为:
printk("%s:%d",filename,line)
使用##的原因是处理arg不代表任何参数的情况,这时候,前面的逗号就变得多余了。使用##之后,GNU C预处理器会丢弃前面的括号,这样,代码:
pr_debug("success")
会被扩展为:
printk("success")
而不是:
printk("success",)
6、标号元素
标C中要求数组或结构体的初始化值必须以固定的顺序出现,在GNU C中,通过指定索引或结构体成员名,允许初始化值以任意顺序出现。
指定数组索引的方法是在初始化值前添加“[INDEX]”,当然也可以用“[FIRST...LAST]=”形式指定一个范围。例如定义一个数组,将其所有元素初始化为0:
unsigned char data[MAX] = {[0...MAX-1]=0};
而结构体的初始化:
{
.llseek = generic_file_llseek;
};
7、当前函数名
GNU C预定义了两个标示符保存当前函数的名字,__FUNCTION__保存函数在源码中的名字,__PRETTY_FUNCTION__保存带语言特色的名字。在C中,这两个名字是相同的。即只是字符串;
8、特殊属性声明
GNU C允许声明函数、变量和类型的特殊属性,以便进行手工的代码优化和定制代码检查的方法。指定一个声明的属性,只需要在申明后添加 __attribute__((ATTRIBUTE))
其中ATTRIBUTE为属性说明,如果存在多个属性,则以逗号分隔。GNU C支持noreturn format section aligned packed等十多个属性
* noreturn属性作用于函数,表示该函数从不返回。这会让编译器优化代码,并消除不必要的的警告信息。例如
#define ATTRIB_NORET __attribute__ ((noreturn)) ....
asmlinkage NORET_TYPE void do_exit(long error_code) ATTRIB_NORET;
*format属性也可用于函数,表示该函数printf scanf 或strftime风格的参数,指定format属性可以让编译器根据格式串检查参数类型。例如:
asmlinkage int printk(const char * fmt,...)\
__attribute__((format(printf,1,2)));
*unused属性作用于函数和变量,表示该函数或变量可能不会被用到,避免编译器产生的警告信息。
*packed属性作用于变量和类型,表示压缩结构体,使用最小的内存。
struct examprl_struct
{
char a;
int b;
long c;
}__attribute__((packed));
注意,这个__attribute__((packed))只能用在GNU C;
属性 section 用于函数和变量,通常编译器将函数放在 .text 节,变量放在.data 或 .bss 节,使用 section 属性,可以让编译器将函数或变量放在指定的节中。例如:
++++ include/linux/init.h
78: #define __init
79: #define __exit
80: #define __initdata
81: #define __exitdata
82: #define __initsetup
83: #define __init_call
84: #define __exit_call
连接器可以把相同节的代码或数据安排在一起,Linux 内核很喜欢使用这种技术,例如系统的初始化代码被安排在单独的一个节,在初始化结束后就可以释放这部分内存。
* aligned (ALIGNMENT)
属性 aligned 用于变量、结构或联合类型,指定变量、结构域、结构或联合的对齐量,以字节为单位,例如:
++++ include/asm-i386/processor.h
294: struct i387_fxsave_struct {
295:
296:
297:
298:
299:
300:
301:
......
308: } __attribute__ ((aligned (16)));
表示该结构类型的变量以 16 字节对齐。通常编译器会选择合适的对齐量,显示指定对齐通常是由于体系限制、优化等原因。
* packed
属性 packed 用于变量和类型,用于变量或结构域时表示使用最小可能的对齐,用于枚举、结构或联合类型时表示该类型使用最小的内存。例如:
++++ include/asm-i386/desc.h
51: struct Xgt_desc_struct {
52:
53:
54: };
域 address 将紧接着 size 分配。属性 packed 的用途大多是定义硬件相关的结
构,使元素之间没有因对齐而造成的空洞。
9、内建函数
GNU C提供了大量的内建函数,其中大部分是标C库函数的GNU C编译器的内建版本。
不属于库函数的其它内建函数的命名通常以__builtin开始;如下所示:
__builtin_return_address(LEVEL);
内建函数 __builtin_return_address 返回当前函数或其调用者的返回地址,参数LEVEL 指定在栈上搜索框架的个数,0 表示当前函数的返回地址,1 表示当前函数的调用者的返回地址,依此类推。例如:
++++ kernel/sched.c
437:
438:
439:
* __builtin_constant_p(EXP)
内建函数 __builtin_constant_p 用于判断一个值是否为编译时常数,如果参数 EXP 的值是常数,函数返回 1,否则返回 0。例如:
++++ include/asm-i386/bitops.h
249: #define test_bit(nr,addr) \
250: (__builtin_constant_p(nr) ? \
251: constant_test_bit((nr),(addr)) : \
252: variable_test_bit((nr),(addr)))
很多计算或操作在参数为常数时有更优化的实现,在 GNU C 中用上面的方法可以根据参数是否为常数,只编译常数版本或非常数版本,这样既不失通用性,又能在参数是常数时编译出最优化的代码。
* __builtin_expect(EXP, C)
内建函数 __builtin_expect 用于为编译器提供分支预测信息,其返回值是整数表达式 EXP 的值,C 的值必须是编译时常数。例如:
++++ include/linux/compiler.h
13: #define likely(x)
14: #define unlikely(x)
++++ kernel/sched.c
564:
565:
566:
567:
这个内建函数的语义是 EXP 的预期值是 C,编译器可以根据这个信息适当地重排语句块的顺序,使程序在预期的情况下有更高的执行效率。上面的例子表示处于中断上下文是很少发生的,第 565-566 行的目标码可能会放在较远的位置,以保证经常执行的目标码更紧凑。
- GNU C与ANSI C
- GNU C与ANSI C
- GNU C与ANSI C
- GNU C与ANSI C
- GNU C与ANSI C
- GNU C与ANSI C
- GNU C 与 ANSI C的区别
- GNU C 与 ANSI C的区别
- GNU C与ANSI C (1)
- GNU C 与 ANSI C的区别
- GNU C 与 ANSI C的区别
- GNU C与ANSI C的区别
- GNU C 与 ANSI C的区别
- GNU C ANSI C
- GNU C 和 ANSI C
- GNU C ANSI C 一些区别
- GNU C 与ANSI C 相比,独特的9个地方
- GNU C 与ANSI C 相比,独特的9个地方(转载
- App Store 创赢艺术--Apple开发的赚钱机密
- Linux内核中的内存(二)
- Effective MySQL之SQL语句最优化,性能改进的实用知识。
- 如何解决问题
- DSS Live env example
- GNU C与ANSI C
- Zookeeper开源客户端框架Curator简介
- DB2里-818错误原因及解决方法
- static in c
- 插件
- 关于局部刷新
- IIS错误解决
- 黑马程序员_IO回顾01
- Android中的Audio播放:控制Audio输出通道切换