文章目录
概述
通常情况下,我们在使用C语言的时候,基本都是使用C语言的标准语法,但GCC编译器提供了许多扩展特性,这些扩展对程序优化、代码安全检查等提供了很强的支持,甚至一部分特性也在后面的C语言标准中进行了实现。本文列举了一部分常见的扩展,更多的扩展可以查阅GCC参考手册。
零长数组
GNU扩展支持使用零长数组,其作用和C99标准中的柔性数组相同,只是在语法定义上存在一些差别。典型零长数组的定义如下:
typedef struct synx_example_s
{
int val;
int zero_array[0]; /* 注意此处和柔性数组的区别 */
}synx_example_t;
在实际使用时,只要保证为结构体分配了足够的内存,就可以利用结构体中零长数组元素进行访问后续的内存空间。
语句表达式
GCC把包含在括号中的复合语句看做是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方,你可以在语句表达式中使用循环、局部变量等,原本只能在复合语句中使用。复合语句的最后一个语句应该是一个表达式,它的值将成为这个语句表达式的值。语句表达式的格式如下:
({表达式1; 表达式2; 表达式3;})
typeof
GCC扩展支持typeof关键字获取表达式的类型,举例说明如下:
#define max(a, b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
offsetof
GCC扩展语法提供了offsetof宏用于返回结构类型中某个成员的偏移地址:
#define offsetof(type, member) __builtin_offsetof (type, member)
__attribute__属性声明
GNU C扩展的__attribute__机制可以用来设置包括类型、变量以及函数的特殊属性。__attribute__书写的语法格式如下:
__attribute__((attribute-list))
其中,attribute-list用于描述设置的属性类型。__attribute__机制可以支持多种属性,常见的属性包括:
- section
- aligned
- packed
- constructor
- regparam
- weak
- noline
section属性
section属性的作用是将修饰的函数或数据放到指定段中,段名由"section_name"定义。seciton属性的使用格式如下:
__attribute__((section("section_name")))
aligned属性
aligned属性以允许程序开发人员自行对结构体的对齐参数进行调整,其基本语法格式如下:
语法格式:__attribute__((aligned(n)))
aligned子项的作用是让所修饰的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。使用示例:
struct struct_memalign {
char char_val;
int int_val;
long long_val;
short short_val;
} __attribute__((aligned(8)));
默认情况下,即使不使用__attribute__((aligned(n))),编译器也会对结构体成员进行对其;若要取消对齐,可以使用__attribute__((packed))对结构体进行修饰
constructor属性
使用contructor属性修饰的函数会在main函数之前执行,可以用来实现全局的构造函数;另外,constructor子项支持指定优先级,从而决定调用次序,优先级取值范围是0-65535,其中0-100是预留的,优先级数值越小优先级越高,越优先被执行调用。只要指定了优先级,就算是指定的优先级是65535也还是会比没有指定优先级的先调用。其基本语法格式如下:
__attribute__((constructor(priority)))
与constructor属性对应的是 destructor 属性,使用destructor属性修饰的函数会在 main函数执行之后或者exit被调用后被自动的执行。
举例说明:
#include<stdio.h>
__attribute__((constructor)) void before_main()
{
printf("before main.\n");
}
__attribute__((destructor)) void after_main()
{
printf("after main.\n");
}
int main()
{
printf("in main.\n");
return 0;
}
执行结果如下:
$ ./main
before main.
in main.
after main.
regparm属性
在 x86体系结构中,默认函数调用过程中将所有参数保存在栈中进行传递。regparm属性会传递一个数值给编译器,这个数值会告诉编译器要用多少个寄存器来传递函数参数。使用格式如下:
__attribute__((regparam(n)))
weak属性
通过weak属性声明,可以将一个强符号转换为弱符号。使用格式如下:
int num __attrubte__((weak));
void __attribute__((weak)) foo(void); // 修饰函数
weak属性在C库函数实现中使用的比较多。
noinline属性
GCC在编译过程中,会尝试对inline关键字修饰的函数以及部分较短的函数进行内联展开,如果不想要GCC的默认内联行为,可以使用noinline属性修饰函数。noinline属性会显式地告诉编译器不要对修饰的函数进行内联展开行为。
__attribute__((noinline)) void foo();
相关参考
- 《GCC工具手册》