GNU __attribute__分析

1 概述

__attribute__机制可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。

主要有用于改变所申明或定义的函数或数据的特性。

2 规范

语法格式为:

__attribute__ ((attribute-list))

其位置约束为:

放于声明的尾部“;”之前。

attribute_适用于函数的声明而不是函数的定义。当需要使用该属性的函数时,必须在同一个文件里进行声明.示例如下:

/* 函数声明 */
void die(const char *format, ...) __attribute__((noreturn))
__attribute__((format(printf,1,2)));

void die(const char *format, ...)
{
/* 函数定义 */
}

在使用__attribute__参数时,你也可以在参数的前后都加上“__”(两个下划线),例如,使用__aligned__而不是aligned,这样,你就可以在相应的头文件里使用它而不用关心头文件里是否有重名的宏定义。

3 函数属性(Function Attribute)

函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。
GNU CC需要使用 –Wall编译器来激活该功能。

3.1 __attribute__ format

该属性告诉编译器,按照printf, scanf, strftime或strfmon的参数表格式规则对该函数的参数进行检查。也即检查函数声明和函数实际调用参数之间的格式化字符串是否匹配。

format的语法格式为:

format (archetype, string-index, first-to-check)

参数说明:

"archetype” 指定是哪种风格;
“string-index” 指定传入函数的第几个参数是格式化字符串
    这里需要注意:成员函数第一个参数为隐含参数this。
“first-to-check” 指定从函数的第几个参数开始按上述规则进行检查。

示例:

extern void myprint(int l,const char *format,...) __attribute__((format(printf,2,3)));

3.2 __attribute__ noreturn

属性 noreturn 用于函数,该属性告诉编译器,此函数从不返回值。

示例:

extern void exit(int)   __attribute__((noreturn));
extern void abort(void) __attribute__((noreturn));

3.3 __attribute__ const

该属性只能用于带有数值类型参数的函数上。

当重复调用带有数值参数的函数时,由于返回值是相同的,所以此时编译器可以进行优化处理,除第一次需要运算外,其它只需要返回第一次的结果就可以了,进而可以提高效率。该属性主要适用于没有静态状态(static state)和副作用的一些函数,并且返回值仅仅依赖输入的参数。

const参数不能用在带有指针类型参数的函数中,因为该属性不但影响函数的参数值,同样也影响到了参数指向的数据,它可能会对代码本身产生严重甚至是不可恢复的严重后果。

该属性的函数不能有任何副作用或者是静态的状态,所以,类似getchar()或time()的函数是不适合使用该属性的。

3.4 -finstrument-functions

该参数可以使程序在编译时,在函数的入口和出口处生成instrumentation调用。恰好在函数入口之后并恰好在函数出口之前,将使用当前函数的地址和调用地址来调用下面的 profiling 函数。

void __cyg_profile_func_enter(void *this_fn, void *call_site);
void __cyg_profile_func_exit(void *this_fn, void *call_site);

第一个参数this_fn是当前函数的起始地址,可在符号表中找到;第二个参数call_site是指调用处地址。
instrumentation 也可用于在其它函数中展开的内联函数。

3.5 no_instrument_function

如果使用了-finstrument-functions ,将在绝大多数用户编译的函数的入口和出口点调用profiling函数。使用该属性,将不进行instrument操作。

3.6 constructor/destructor

若函数被设定为constructor属性,则该函数会在main()函数执行之前被自动的执行。类似的,若函数被设定为destructor属性,则该函数会在main()函数执行之后或者exit()被调用后被自动的执行。拥有此类属性的函数经常隐式的用在程序的初始化数据方面。

3.7 unused

属性 unused 用于函数和变量,表示该函数或变量可能不使用,这个属性可以避免
编译器产生警告信息。

3.8 section ("section-name")

属性 section 用于函数和变量,通常编译器将函数放在 .text 节,变量放在
.data 或 .bss 节,使用 section 属性,可以让编译器将函数或变量放在指定的
节中。

3.9 __builtin_return_address (LEVEL)

内建函数 __builtin_return_address 返回当前函数或其调用者的返回地址,参数
LEVEL 指定在栈上搜索框架的个数,0 表示当前函数的返回地址,1 表示当前函数
的调用者的返回地址,依此类推。

3.10 __builtin_constant_p(EXP)

内建函数 __builtin_constant_p 用于判断一个值是否为编译时常数,如果参数
EXP 的值是常数,函数返回 1,否则返回 0

3.11 __builtin_expect(EXP, C)

内建函数 __builtin_expect 用于为编译器提供分支预测信息,其返回值是整数表
达式 EXP 的值,C 的值必须是编译时常数

4 变量属性(Variable Attributes)

关键字__attribute__也可以对变量(variable)或结构体成员(structure field)进行属性设置。

4.1 aligned (alignment)

属性 aligned 用于变量、结构或联合类型,指定变量、结构域、结构或联合的对齐量,以字节为单位。aligned属性使被设置的对象占用更多的空间,该属性规定变量或结构体成员的最小的对齐格式。例如:

//编译器将以16字节(注意是字节byte不是位bit)对齐的方式分配一个变量
int x __attribute__ ((aligned (16))) = 0; 

//创建一个双字对齐的int
struct foo { int x[2] __attribute__ ((aligned (8))); }; 

//如果aligned后面不紧跟一个指定的数字值,那么编译器将依据你的目标机器情况使用最大最有益的对齐方式
short array[3] __attribute__ ((aligned));

4.2 packed

属性 packed 用于变量和类型,用于变量或结构域时表示使用最小可能的对齐,用于枚举、结构或联合类型时表示该类型使用最小的内存。packed可以减小对象占用的空间.使用该属性可以使得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐。

例如:

//域 address 将紧接着 size 分配。
//属性 packed 的用途大多是定义硬件相关的结构,使元素之间没有因对齐而造成的空洞。
struct Xgt_desc_struct {
    unsigned short size;
    unsigned long address __attribute__((packed));
};

4.3 其他

可选的属性值还可以是:

cleanup,common,nocommon,deprecated,mode,section,shared,tls_model,
transparent_union,unused,vector_size,weak,dllimport,dlexport等,

5 类型属性(Type Attribute)

关键字attribute也可以对结构体(struct)或共用体(union)进行属性设置。大致有六个参数值可以被设定,即:aligned, packed, transparent_union, unused, deprecated 和 may_alias。

其用法与4中用法类似,可以参考上面的内容。

6 同时使用多属性

可以在同一个函数声明里使用多个attribute,并且实际应用中这种情况是十分常见的。

示例:

/* 把类似printf的消息传递给stderr 并退出 */
extern void die(const char *format, ...)
__attribute__((noreturn))
__attribute__((format(printf, 1, 2)));
//或者写成
extern void die(const char *format, ...)
__attribute__((noreturn, format(printf, 1, 2)));

7 非GNU处理

如果使用的是非GNU C, 那么就忽略__attribute__,忽略方法如下:

#ifndef __GNUC__
# define __attribute__(x) /*NOTHING*/
#endif
发布了46 篇原创文章 · 获赞 66 · 访问量 6万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章