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("%02x", s.data[i]);
- 变量长度数组
GNU C中也可以使用 1 个变量定义数组,例如如下代码中定义 double x[n]:
int main(int argc, char **argv)
{
int i, n = argc;
double x[n];
for (i = 0; i < n; i++)
x[i] = i;
return 0;
}
2 宏定义语句表达式
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 = min_t(float, fa, fb);
3 typeof 关键字
typeof(x)语句可以获得 x 得类型,可以借助typeof重定义宏。
#define min_t(x, y) \
( { typeof(x) __x = (x); \
typeof(x) __y = (y); \
__x < __y? __x : __y; \
})
4 可变参数宏
标准c 就支持可变参数函数,意味着函数得参数时不固定得,例如printf() 函数得原型为:
printf(const char *fmt, arg...);
在 GNU c 中,宏也可接收可变数目得参数,例如:
#define pr_debug(fmt, atg...) prink(fmt, ##arg)
使用 ## 是为了处理arg不代表任何参数得情况,此时,前面的逗号就多余了,使用 ## 后,GNU预处理器会丢弃前面的逗号。
5 标号元素
标准 C 要求数组或结构体的初始化值必须以固定的顺序出现,在GNU C 中,通过指定索引或结构体成员名称,允许初始化值以任意顺序出现。
指定数组索引的方法是在初始化值前加“[index] =”,当然也可以用 "[fisrt ... last]="的形式指定一个范围。例如:
unsigned char data[MAX] = { [0 ... MAX - 1] = 0};
结构体初始化,例如:
struct test_t a =
{
.lseek = 1,
.read = 2,
};
6 特殊属性声明
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 (printk, 1, 2)));
- unused 作用于未用到的函数或变量,用于消除编译警告。
- aligned 作用指定变量、结构体、联合体的对齐方式,以字节为单位。
struct example_struct
{
char a;
int b;
long c;
} __attribute__((aligned(4)));
- packed 属性用于变量或结构体成员时表示最小可能的对齐,用于枚举、结构体或联合体类型时表示该类型使用最小内存。
struct example_struct
{
char a;
int b;
long b __attribute__((packed));
};
7 内建函数
GNU C 提供了大量内建函数,其中大部分标准 C 库函数的 GNU C 库的内建版本,例如 memcpy() 等,它们与对应的标准 C 库函数功能相同。
不属于标准库函数的其它内建函数的命名通常以 __builtin 开始,如下所示。
- 内建函数 __builtin_return_address(LEVEL),返回当前函数或其调用者的返回地址,参数 LEVEL 用于指定调用栈的级数,如 0 表示当前函数的返回地址,1 表示当前函数的调用者的返回地址。
注意:在使用 gcc 编译 c 程序的时候,如果使用 “-ansi -pedantic” 编译选项,则会告诉编译器不适用 GNU 的扩展语法。使用上述特性就会出现编译告警。