GNU C 对标准C进行一系列扩展,以增强标准C的功能。
1、零长度和变量长度数组
GNU C 允许使用零长度数组,比如 char data[0];
GNU C 允许使用一个变量定义数组的长度如:
int n=0;
scanf("%d",&n);
int array[n];
2、case 范围
GNU C支持 case x...y这样的语法,[x,y]之间数均满足条件。
case 'a'...'z': /*from 'a' to 'z'*/
break
3、语句表达式
GNU C 把包含在括号中的复合语句看作是一个表达式,称为语句表达式。
#define min_t(type,x,y)\
({type __x=(x); type __y=(y);__x<__y?__x:__y;})
这种写法可以避免
#define min_t(x,y) ((x)<(y)?(x):(y))
在min_t(x++,++y)中出现的副作用
4、typeof 关键字
typeof(x)可以获得x的类型借助typeof关键字我们可以重新定义min_t:
#define min_t(x,y)\
({typeof(x) __x=(x); typeof(y) __y=(y);__x<__y?__x:__y;})
5、可变参数宏
GNU C中宏也支持可变参数
#define pr_debug(fmt,arg...) \
printk(fmt,##arg)
这里使用##的原因是处理arg不代表任何参数的情况,这时候,前面的逗号就变得多余使用##之后GNU C编译器会丢弃前面的逗号。
6、标号元素
标准C要求数组或结构体的初始化值必须以固定的顺序出现,在GNU C中,通过指定索引或结构体成员名,允许初始化以任意顺序出现。
unsigned char data[MAX] ={
[0]=10,
[10]=100,
};
struct file_operations ext2_file_operations={
open:ext2_open,
close:ext2_close,
};
在linux 2.6中推荐如下方式
struct file_operations ext2_file_operations={
.read=ext2_read,
.write=ext2_write,
};
7、当前函数名
GNU C中预定义两个标志符保存当前函数的名字,__FUNCTION__保存函数在源码中的名字, __PRETTY__FUNCTION__保存带语言特色的名字。在C函数中这两个名字是相同的.
void func_example()
{
printf("the function name is %s",__FUNCTION__);
}
在C99中支持__func__宏,因此建议使用__func__替代__FUNCTION__
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;
struct example_struct{
char a;
int b;
long c;
} __attribute__((aligned(4)));
上述表示结构体以四个字节对齐
struct example_struct{
char a;
int b;
long c;
} __attribute__((packed));
9、内建函数
GNU C提供了大量的内建函数,例如memcpy,不属于库函数的其他内建函数的命名通常以__buildin开始,如下所示。
内建函数__builtin_return_address(LEVEL)返回当前函数或其调用者的返回地址,参数LEVEL指定调用栈的级数,如0表示当前函数的返回地址,1表示当前函数调用者的返回地址。
内建函数__builtin_constant_p(EXP,C)用于为编译器提供分支预测信息,其返回值是整数表达式EXP的值,C的值必须是编译常数。
示例代码:
#define test_bit(nr,addr) \
(__builtin_constant_p(nr))? \
constant_test_bit((nr),(addr)):\
variable_test_bit((nr),(addr))
若不想使用GNU C扩展,那么只需要在gcc参数后面加上 -ansi -pedantic即可,使用上述参数后,所有GNC C扩展语法部分将会有编译警报。