浅析GNU C扩展语法

概述

通常情况下,我们在使用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工具手册》
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值