__attribute__ 你知多少?
GNU C 的⼀⼤特⾊就是__attribute__ 机制。__attribute__ 可以设置函数属性(Function Attribute )、变量属性(Variable Attribute )和类型属性(Type Attribute )。
__attribute__ 书写特征是:__attribute__ 前后都有两个下划线,并切后⾯会紧跟⼀对原括弧,括弧⾥⾯是相应的__attribute__ 参数。
__attribute__ 语法格式为:__attribute__ ((attribute-list))其位置约束为:放于声明的尾部“ ;” 之前。
关键字__attribute__ 也可以对结构体(struct )或共⽤体(union )进⾏属性设置。⼤致有六个参数值可以被设定,即:aligned, packed, transparent_union, unused, deprecated 和 may_alias 。
在使⽤__attribute__ 参数时,你也可以在参数的前后都加上“__” (两个下划线),例如,使⽤__aligned__⽽不是aligned ,这样,你就可以在相应的头⽂件⾥使⽤它⽽不⽤关⼼头⽂件⾥是否有重名的宏定义。aligned (alignment)
该属性设定⼀个指定⼤⼩的对齐格式(以字节 为单位),例如:struct S {short b[3];
} __attribute__ ((aligned (8)));
typedef int int32_t __attribute__ ((aligned (8)));
该声明将强制编译器确保(尽它所能)变量类 型为struct S 或者int32_t 的变量在分配空间时采⽤8 字节对齐⽅式。如上所述,你可以⼿动指定对齐的格式,同 样,你也可以使⽤默认的对齐⽅式。如果aligned 后⾯不紧跟⼀个指定的数字值,那么编译器将依据你的⽬标机器情况使⽤最⼤最有益的对齐⽅式。例如:struct S {short b[3];
} __attribute__ ((aligned));
这⾥,如果sizeof (short )的⼤⼩为2 (byte ),那么,S 的⼤⼩就为6 。取⼀个2 的次⽅值,使得该值⼤于等于6 ,则该值为8 ,所以编译器将设置S 类型的对齐⽅式为8 字节。
aligned 属性使被设置的对象占⽤更多的空间,相反的,使⽤packed 可以减⼩对象占⽤的空间。
需要注意的是,attribute 属性的效⼒与你的连接器也有关,如果你的连接器最⼤只⽀持16 字节对齐,那么你此时定义32 字节对齐也是⽆济于事的。packed
使⽤该属性对struct 或者union 类型进⾏定义,设定其类型的每⼀个变量的内存约束。当⽤在enum 类型 定义时,暗⽰了应该使⽤最⼩完整的类型(it indicates that the smallest integral type should be used)。
下⾯的例⼦中,packed_struct 类型的变量数组中的值将会紧紧的靠在⼀起,但内部的成员变量s 不会被“pack” ,如果希望内部的成员变量也被packed 的话,unpacked-struct 也需要使⽤packed 进⾏相应的约束。struct unpacked_struct{
char c;
int i;};
struct packed_struct{ char c; int i;
struct unpacked_struct s;}__attribute__ ((__packed__));
下⾯的例⼦中使⽤__attribute__ 属性定义了⼀些结构体及其变量,并给出了输出结果和对结果的分析。程序代 码为:
1 struct p 2 3 { 4
5 int a; 6
7 char b; 8
9 short c;10
11 }__attribute__((aligned(4))) pp;12
13 struct m14 15 {16
17 char a;18
19 int b;20
21 short c;22
23 }__attribute__((aligned(4))) mm;24
25 struct o26 27 {28
29 int a;30
31 char b;32
33 short c;34 35 }oo;36
37 struct x38 39 {40
41 int a;42
43 char b;44
45 struct p px;46
47 short c;48
49 }__attribute__((aligned(8))) xx;50
51 int main()
52 53 {54
55 printf(\"sizeof(int)=%d,sizeof(short)=%d.sizeof(char)=%d\\n\",sizeof(int),sizeof(short),sizeof(char));56
57 printf(\"pp=%d,mm=%d \\n\", sizeof(pp),sizeof(mm));58
59 printf(\"oo=%d,xx=%d \\n\", sizeof(oo),sizeof(xx));60
61 return 0;62 63 }
输出结 果:
sizeof(int)=4,sizeof(short)=2.sizeof(char)=1pp=8,mm=12oo=8,xx=24分析:sizeof(pp):
sizeof(a)+sizeof(b)+sizeof(c)=4+1+1=6<8 所以sizeof(pp)=8sizeof(mm):
sizeof(a)+sizeof(b)+sizeof(c)=1+4+2=7
但是 a 后⾯需要⽤ 3 个字节填充,但是 b 是 4 个字节,所以 a 占⽤ 4 字节, b 占⽤ 4 个字节,⽽ c ⼜要占⽤ 4 个字节。所以 sizeof(mm)=12sizeof(oo):
sizeof(a)+sizeof(b)+sizeof(c)=4+1+2=7因为默 认是以4 字节对齐,所以sizeof(oo)=8sizeof(xx):
sizeof(a)+ sizeof(b)=4+1=5
sizeof(pp)=8; 即xx 是采⽤8 字节对齐的,所以要在a ,b 后⾯添3 个空余字节,然后才能存储px ,4+1+ (3 )+8+1=17
因为xx 采⽤的对齐是8 字节对齐,所以xx 的⼤⼩必定是8 的整数倍,即xx 的⼤⼩是⼀个⽐17 ⼤⼜是8 的倍数的⼀个最⼩值,由此得到17<24 ,所以sizeof(xx)=24
函数属性(Function Attribute)
函数属性可以帮助开发者把⼀些特性添加到函数声明中,从⽽可以使编译器在错误检查⽅⾯的功能更强⼤。__attribute__机制也很容易同⾮GNU应⽤程序做到兼容之功效。
GNU CC需要使⽤ –Wall编译器来击活该功能,这是控制警告信息的⼀个很好的⽅式。下⾯介绍⼏个常见的属性参数。
__attribute__ format
该__attribute__属性可以给被声明的函数加上类似printf或者scanf的特征,它可以使编译器检查函数声明和函数实际调⽤参数之间的格式化字符串是否匹配。该功能⼗分有⽤,尤其是处理⼀些很难发现的bug。format的语法格式为:
format (archetype, string-index, first-to-check) format属性告诉编译器,按照printf, scanf,
strftime或strfmon的参数表格式规则对该函数的参数进⾏检查。“archetype”指定是哪种风格;“string-index”指定传⼊函数的第⼏个参数是格式化字符串;“first-to-check”指定从函数的第⼏个参数开始按上述规则进⾏检查。具体使⽤格式如下:
__attribute__((format(printf,m,n)))__attribute__((format(scanf,m,n)))其中参数m与n的含义为:
m:第⼏个参数为格式化字符串(format string);
n:参数集合中的第⼀个,即参数“…”⾥的第⼀个参数在函数参数总数排在第⼏,注意,有时函数参数⾥还有“隐⾝”的呢,后⾯会提到;
在使⽤上,__attribute__((format(printf,m,n)))是常⽤的,⽽另⼀种却很少见到。下⾯举例说明,其中myprint为⾃⼰定义的⼀个带有可变参数的函数,其功能类似于printf:
//m=1;n=2
extern void myprint(const char *format,...) __attribute__((format(printf,1,2)));//m=2;n=3
extern void myprint(int l,const char *format,...) __attribute__((format(printf,2,3)));
需要特别注意的是,如果myprint是⼀个函数的成员函数,那么m和n的值可有点“悬乎”了,例如://m=3;n=4
extern void myprint(int l,const char *format,...) __attribute__((format(printf,3,4)));
其原因是,类成员函数的第⼀个参数实际上⼀个“隐⾝”的“this”指针。(有点C++基础的都知道点this指针,不知道你在这⾥还知道吗?)
这⾥给出测试⽤例:attribute.c,代码如下:
1:
2:extern void myprint(const char *format,...) __attribute__((format(printf,1,2)));3:
4:void test()5:{
6: myprint(\"i=%d\\n\",6);7: myprint(\"i=%s\\n\",6);8: myprint(\"i=%s\\n\",\"abc\");9: myprint(\"%s,%d,%d\\n\",1,2);10:}
运⾏$gcc –Wall –c attribute.c attribute后,输出结果为:attribute.c: In function `test':
attribute.c:7: warning: format argument is not a pointer (arg 2)attribute.c:9: warning: format argument is not a pointer (arg 2)attribute.c:9: warning: too few arguments for format
如果在attribute.c中的函数声明去掉__attribute__((format(printf,1,2))),再重新编译,既运⾏$gcc –Wall –c attribute.cattribute后,则并不会输出任何警告信息。
注意,默认情况下,编译器是能识别类似printf的“标准”库函数。__attribute__ noreturn
该属性通知编译器函数从不返回值,当遇到类似函数需要返回值⽽却不可能运⾏到返回值处就已经退出来的情况,该属性可以避免出现错误信息。C库函数中的abort()和exit()的声明格式就采⽤了这种格式,如下所⽰:extern void exit(int) __attribute__((noreturn));extern void abort(void) __attribute__((noreturn)); 为了⽅便理解,⼤家可以参考如下的例⼦:
1 //name: noreturn.c ;测试__attribute__((noreturn)) 2 extern void myexit(); 3
4 int test(int n) 5 {
6 if ( n > 0 ) 7 {
8 myexit();
9 /* 程序不可能到达这⾥*/
10 }11 else
12 return 0;13 }
编译显⽰的输出信息为:
$gcc –Wall –c noreturn.cnoreturn.c: In function `test':
noreturn.c:12: warning: control reaches end of non-void function
警告信息也很好理解,因为你定义了⼀个有返回值的函数test却有可能没有返回值,程序当然不知道怎么办了!加上__attribute__((noreturn))则可以很好的处理类似这种问题。把extern void myexit();修改为:
extern void myexit() __attribute__((noreturn));之后,编译不会再出现警告信息。__attribute__ const
该属性只能⽤于带有数值类型参数的函数上。当重复调⽤带有数值参数的函数时,由于返回值是相同的,所以此时编译器可以进⾏优化处理,除第⼀次需要运算外, 其它只需要返回第⼀次的结果就可以了,进⽽可以提⾼效率。该属性主要适⽤于没有静态状态(static state)和副作⽤的⼀些函数,并且返回值仅仅依赖输⼊的参数。为了说明问题,下⾯举个⾮常“糟糕”的例⼦,该例⼦将重复调⽤⼀个带有相同参数值的函数,具体如下:
extern int square(int n) __attribute__ ((const));... for (i = 0; i < 100; i++ ) { total += square (5)+ i; }
通过添加__attribute__((const))声明,编译器只调⽤了函数⼀次,以后只是直接得到了相同的⼀个返回值。
事实上,const参数不能⽤在带有指针类型参数的函数中,因为该属性不但影响函数的参数值,同样也影响到了参数指向的数据,它可能会对代码本⾝产⽣严重甚⾄是不可恢复的严重后果。
并且,带有该属性的函数不能有任何副作⽤或者是静态的状态,所以,类似getchar()或time()的函数是不适合使⽤该属性的。
-finstrument-functions
该参数可以使程序在编译时,在函数的⼊⼝和出⼝处⽣成instrumentation调⽤。恰好在函数⼊⼝之后并恰好在函数出⼝之前,将使⽤当前函数的地址和调⽤地址来调⽤下⾯的profiling
函数。(在⼀些平台上,__builtin_return_address不能在超过当前函数范围之外正常⼯作,所以调⽤地址信息可能对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
也可⽤于在其它函数中展开的内联函数。从概念上来说,profiling调⽤将指出在哪⾥进⼊和退出内联函数。这就意味着这种函数必须具有可寻址形式。如 果函数包含内联,⽽所有使⽤到该函数的程序都要把该内联展开,这会额外地增加代码长度。如果要在C 代码中使⽤extern inline声明,必须提供这种函数的可寻址形式。
可对函数指定no_instrument_function属性,在这种情况下不会进⾏ Instrumentation操作。例如,可以在以下情况下使⽤no_instrument_function属性:上⾯列出的profiling函 数、⾼优先级的中断例程以及任何不能保证profiling正常调⽤的函数。
no_instrument_function
如果使⽤了-finstrument-functions
,将在绝⼤多数⽤户编译的函数的⼊⼝和出⼝点调⽤profiling函数。使⽤该属性,将不进⾏instrument操作。constructor/destructor
若函数被设定为constructor属性,则该函数会在main()函数执⾏之前被⾃动的执⾏。类似的,若函数被设定为destructor属性,则该 函数会在main()函数执⾏之后或者exit()被调⽤后被⾃动的执⾏。拥有此类属性的函数经常隐式的⽤在程序的初始化数据⽅⾯。这两个属性还没有在⾯向对象C中实现。同时使⽤多个属性
可以在同⼀个函数声明⾥使⽤多个__attribute__,并且实际应⽤中这种情况是⼗分常见的。使⽤⽅式上,你可以选择两个单独的__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))); 如果带有该属性的⾃定义函数追加到库的头⽂件⾥,那么
所以调⽤该函数的程序都要做相应的检查。
和⾮GNU编译器的兼容性
庆幸的是,__attribute__设计的⾮常巧妙,很容易作到和其它编译器保持兼容,也就是说,如果⼯作在其它的⾮GNU编译器上,可以很容易的忽略该属性。即使__attribute__使⽤了多个参数,也可以很容易的使⽤⼀对圆括弧进⾏处理,例如:
/* 如果使⽤的是⾮GNU C, 那么就忽略__attribute__ */#ifndef __GNUC__# define __attribute__(x) /*NOTHING*/#endif
需要说明的是,__attribute__适⽤于函数的声明⽽不是函数的定义。所以,当需要使⽤该属性的函数时,必须在同⼀个⽂件⾥进⾏声明,例如:
/* 函数声明 */void die(const char *format, ...) __attribute__((noreturn)) __attribute__((format(printf,1,2))); void die(const char *format, ...){ /* 函数定义 */}
Specifying Attributes of Variables
aligned (alignment)This attribute specifies a minimum alignment for the variable or structure field, measured in bytes.
For example, the declaration:
int x __attribute__ ((aligned (16))) = 0;
causes the compiler to allocate the global variable x on a 16-byte boundary. On a 68040, this could be used inconjunction with an asm expression to access themove16 instruction which requires 16-byte aligned operands.You can also specify the alignment of structure fields. For example, to create a double-word aligned int pair, youcould write:
struct foo { int x[2] __attribute__ ((aligned (8))); };
This is an alternative to creating a union with a double member that forces the union to be double-word aligned.As in the preceding examples, you can explicitly specify the alignment (in bytes) that you wish the compiler to usefor a given variable or structure field. Alternatively, you can leave out the alignment factor and just ask the compilerto align a variable or field to the maximum useful alignment for the target machine you are compiling for. Forexample, you could write:
short array[3] __attribute__ ((aligned));
for more: http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes
下⾯来看⼀个不⼀样的HelloWorld程序:1234
5#include static __attribute__((constructor)) void before()7{ 8 printf(\"Hello\");9} 10static __attribute__((destructor)) void after()11{ printf(\" World!\\n\");12}13 int main(int args,char ** argv)14{ 15 return EXIT_SUCCESS;16}1718 19 我们知道这是⼀个HelloWorld程序,所以输出的结果就是\"Hello World!\",很简单,不需要对这点过多关⼼.下⾯我们来关⼼关⼼别的:1 __attribute__((constructor))2__attribute__((destructor))3 解释⼀下:__attribute__((constructor)) 在main() 之前执⾏,__attribute__((destructor)) 在main()执⾏结束之后执⾏.上⾯的例⼦中我没有在main函数中添加任何的输出,所以看不到具体的信息.这点可以⾃⼰尝试~ 如果要在main()之前或者是执⾏完成之后,需要执⾏很多的前处理动作或者是后处理动作,我们应该怎么处理?也许,你需要下⾯这些东西: __attribute__((constructor(PRIORITY)))__attribute__((destructor(PRIORITY))) PRIORITY: 优先级.好吧,下⾯就来试试: 执⾏的输出如下: 从输出的信息看,前处理都是按照优先级先后执⾏的,⽽后处理则是相反的,好吧,我们使⽤GDB调试验证⼀下: 从调试的信息也是验证了上⾯的结果. 另外⼀个问题,优先级有没有范围的? 其实刚开始我写的程序中的优先级是1,我们将上⾯的程序改⼀下,然后编译看⼀下会有什么样的结果: 0-100(包括100),是内部保留的,所以在编码的时候需要注意. 关于__attribute__的⽤法,可以有另外⼀种写法,先声明函数,然后再定义. glibc多采⽤第⼀种写法. 关于linux内核中的\"__attribute__ ((packed))\" 引⽤: __attrubte__ ((packed)) 的作⽤就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占⽤字节数进⾏对齐。#define __u8 unsigned char#define __u16 unsigned short /* __attribute__ ((packed)) 的位置约束是放于声明的尾部“;”之前 */struct str_struct{ __u8 a; __u8 b; __u8 c; __u16 d; } __attribute__ ((packed)); /* 当⽤到typedef时,要特别注意__attribute__ ((packed))放置的位置,相当于: * typedef struct str_stuct str; * ⽽struct str_struct 就是上⾯的那个结构。 */ typedef struct { __u8 a; __u8 b; __u8 c; __u16 d; } __attribute__ ((packed)) str; /* 在下⾯这个typedef结构中,__attribute__ ((packed))放在结构名str_temp之后,其作⽤是被忽略的,注意与结构str的区别。*/typedef struct { __u8 a; __u8 b; __u8 c; __u16 d; }str_temp __attribute__ ((packed));typedef struct { __u8 a; __u8 b; __u8 c; __u16 d;}str_nopacked;int main(void) { printf(\"sizeof str = %d\\n\ printf(\"sizeof str_struct = %d\\n\ printf(\"sizeof str_temp = %d\\n\ printf(\"sizeof str_nopacked = %d\\n\ return 0;} 编译运⾏:引⽤: [root@localhost root]# ./packedtest sizeof str = 5 sizeof str_struct = 5sizeof str_temp = 6 sizeof str_nopacked = 6 GNU C的⼀⼤特⾊就是__attribute__机制。__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。 __attribute__书写特征是:__attribute__前后都有两个下划线,并且后⾯会紧跟⼀对括弧,括弧⾥⾯是相应的__attribute__参数。 __attribute__语法格式为:__attribute__ ((attribute-list)) 其位置约束:放于声明的尾部“;”之前。 函数属性(Function Attribute):函数属性可以帮助开发者把⼀些特性添加到函数声明中,从⽽可以使编译器在错误检查⽅⾯的功能更强⼤。__attribute__机制也很容易同⾮GNU应⽤程序做到兼容之功效。GNU CC需要使⽤ –Wall编译器来击活该功能,这是控制警告信息的⼀个很好的⽅式。 packed属性:使⽤该属性可以使得变量或者结构体成员使⽤最⼩的对齐⽅式,即对变量是⼀字节对齐,对域(field)是位对齐。 ⽹络通信通常分为基于数据结构的和基于流的。HTTP协议就是后者的⼀个例⼦。 有时为了提⾼程序的处理速度和数据处理的⽅便,会使⽤基于数据结构的通信(不需要对流进⾏解析)。但是,当需要在多平台间进⾏通信时,基于数据结构的通信,往往要⼗分注意以下⼏个⽅⾯:[1] 字节序[2] 变量长度[3] 内存对齐 在常见的系统架构中(Linux X86,Windows),⾮单字节长度的变量类型,都是低字节在前,⽽在某些特定系统中,如Soalris Sparc平台,⾼字节在前。如果在发送数据前不进⾏处理,那么由Linux X86发向Soalris Sparc平台的数据值,势必会有极⼤的偏差,进⽽程序运⾏过程中⽆法出现预计的正常结果,更严重时,会导致段错误。 对于此种情况,我们往往使⽤同⼀的字节序。在系统中,有ntohXXX(), htonXXX()等函数,负责将数据在⽹络字节序和本地字节序之间转换。虽然每种系统的本地字节序不同,但是对于所有系统来说,⽹络字节序是固定的 -----⾼字节在前。所以,可以以⽹络字节序为通信的标准,发送前,数据都转换为⽹络字节序。 转换的过程,也建议使⽤ntohXXX(), htonXXX()等标准函数,这样代码可以轻松地在各平台间进⾏移植(像通信这种很少依赖系统API的代码,做成通⽤版本是不错的选择)。 变量的长度,在不同的系统之间会有差别,如同是Linux2.6.18的平台,在位系统中,指针的长度为8个字节,⽽在32位系统中,指针⼜是4个字 节的长度---此处只是举个例⼦,很少有⼈会将指针作为数据发送出去。下⾯是我整理的在位Linux系统和32位Linux系统中,⼏种常见C语⾔变 量的长度: short int long long long ptr time_t32位 2 4 4 8 4 4位 2 4 8 8 8 8 在定义通信⽤的结构体时,应该考虑使⽤定常的数据类型,如uint32_t,4字节的固定长度,并且这属于标准C库(C99),在各系统中都可使⽤。 内存对齐的问题,也与系统是位还是32位有关。如果你⼿头有32位和位系统,不妨写个简单的程序测试⼀下,你就会看到同⼀个结构体,即便使⽤了定 常的数据类型,在不同系统中的⼤⼩是不同的。对齐往往是以4字节或8字节为准的,只要你写的测试程序,变量所占空间没有对齐到4或8的倍数即可,举个简单 的测试⽤的结构体的例⼦吧:struct student{ char name[7]; uint32_t id; char subject[5]; }; 在每个系统上看下这个结构体的长度吧。 内存对齐,往往是由编译器来做的,如果你使⽤的是gcc,可以在定义变量时,添加__attribute__,来决定是否使⽤内存对齐,或是内存对齐到⼏个字节,以上⾯的结构体为例: 1)到4字节,同样可指定对齐到8字节。struct student{ char name[7]; uint32_t id; char subject[5]; } __attribute__ ((aligned(4))); 2)不对齐,结构体的长度,就是各个变量长度的和struct student{ char name[7]; uint32_t id; char subject[5]; } __attribute__ ((packed)); One of the best (but little known) features of GNU C is the __attribute__ mechanism, which allows a developer toattach characteristics to function declarations to allow the compiler to perform more error checking. It was designedin a way to be compatible with non-GNU implementations, and we've been using this for years in highly portablecode with very good results. Table of Contents 1. __attribute__ format2. __attribute__ noreturn3. __attribute__ const4. Putting them together 5. Compatibility with non-GNU compilers6. Other References Note that __attribute__ spelled with two underscores before and two after, and there are always two sets of parentheses surrounding the contents. There is a good reason for this - see below. Gnu CC needs to use the -Wall compiler directive to enable this (yes, there is a finer degree of warnings control available, but we are very bigfans of max warnings anyway). __attribute__ format This __attribute__ allows assigning printf-like or scanf-like characteristics to the declared function, and this enablesthe compiler to check the format string against the parameters provided throughout the code. Thisis exceptionally helpful in tracking down hard-to-find bugs.There are two flavors: __attribute__((format(printf,m,n)))__attribute__((format(scanf,m,n))) but in practice we use the first one much more often. The (m) is the number of the \"format string\" parameter, and (n) is the number of the first variadic parameter. To seesome examples: /* like printf() but to standard error only */extern void eprintf(const char *format, ...) __attribute__((format(printf, 1, 2))); /* 1=format 2=params */ /* printf only if debugging is at the desired level */extern void dprintf(int dlevel, const char *format, ...) __attribute__((format(printf, 2, 3))); /* 2=format 3=params */ With the functions so declared, the compiler will examine the argument lists $ cat test.c 1 extern void eprintf(const char *format, ...)2 __attribute__((format(printf, 1, 2)));3 4 void foo()5 { 6 eprintf(\"s=%s\\n\error on this line */7 8 eprintf(\"n=%d,%d,%d\\n\error on this line */9 } $ cc -Wall -c test.ctest.c: In function `foo': test.c:6: warning: format argument is not a pointer (arg 2)test.c:8: warning: too few arguments for format Note that the \"standard\" library functions - printf and the like - are already understood by the compiler by default. __attribute__ noreturn This attribute tells the compiler that the function won't ever return, and this can be used to suppress errors aboutcode paths not being reached. The C library functions abort() and exit() are both declared with this attribute: extern void exit(int) __attribute__((noreturn));extern void abort(void) __attribute__((noreturn)); Once tagged this way, the compiler can keep track of paths through the code and suppress errors that won't everhappen due to the flow of control never returning after the function call. In this example, two nearly-identical C source files refer to an \"exitnow()\" function that never returns, but withoutthe __attribute__tag, the compiler issues a warning. The compiler is correct here, because it has no way ofknowing that control doesn't return. $ cat test1.c extern void exitnow(); int foo(int n){ if ( n > 0 ) { exitnow(); /* control never reaches this point */ } else return 0;} $ cc -c -Wall test1.ctest1.c: In function `foo': test1.c:9: warning: this function may return with or without a value But when we add __attribute__, the compiler suppresses the spurious warning: $ cat test2.c extern void exitnow() __attribute__((noreturn));int foo(int n){ if ( n > 0 ) exitnow(); else return 0;} $ cc -c -Wall test2.cno warnings! __attribute__ const This attribute marks the function as considering only its numeric parameters. This is mainly intended for thecompiler to optimize away repeated calls to a function that the compiler knows will return the same value repeatedly. It applies mostly to math functions that have no static state or side effects, and whose return is solelydetermined by the inputs. In this highly-contrived example, the compiler normally must call the square() function in every loop even thoughwe know that it's going to return the same value each time: extern int square(int n) __attribute__((const));... for (i = 0; i < 100; i++ ) { total += square(5) + i; } By adding __attribute__((const)), the compiler can choose to call the function just once and cache the return value.In virtually every case, const can't be used on functions that take pointers, because the function is not consideringjust the function parameters but also the data the parameters point to, and it will almost certainly break the codevery badly in ways that will be nearly impossible to track down. Furthermore, the functions so tagged cannot have any side effects or static state, so thingslike getchar() or time() would behave very poorly under these circumstances. Putting them together Multiple __attributes__ can be strung together on a single declaration, and this is not uncommon in practice. Youcan either use two separate __attribute__s, or use one with a comma-separated list: /* send printf-like message to stderr and exit */extern void die(const char *format, ...) __attribute__((noreturn)) __attribute__((format(printf, 1, 2)));/*or*/ extern void die(const char *format, ...) __attribute__((noreturn, format(printf, 1, 2))); If this is tucked away safely in a library header file, all programs that call this function receive this checking. Compatibility with non-GNU compilers Fortunately, the __attribute__ mechanism was cleverly designed in a way to make it easy to quietly eliminate themif used on platforms other than GNU C. Superficially, __attribute__ appears to have multiple parameters (whichwould typically rule out using a macro), but the two sets of parentheses effectively make it a single parameter, andin practice this works very nicely. /* If we're not using GNU C, elide __attribute__ */#ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/#endif Note that __attribute__ applies to function declarations, not definitions, and we're not sure why this is. So whendefining a function that merits this treatment, an extra declaration must be used (in the same file): /* function declaration */ void die(const char *format, ...) __attribute__((noreturn)) __attribute__((format(printf,1,2)));void die(const char *format, ...){ /* function definition */} Other References We'll note that there are many more attributes available, including those for variables and types, and they are notcovered here: we have chosen to just touch on the high points. Those wishing more information can find it in theGNU online documentation athttp://gcc.gnu.org:GCC 4.0 GCC 4.0 Function Attributes GCC 4.0 Variable Attributes GCC 4.0 Type Attributes GCC 3.2 GCC 3.2 Function Attributes GCC 3.2 Variable Attributes GCC 3.2 Type AttributesGCC 3.1 GCC 3.1 Function Attributes GCC 3.1 Variable Attributes GCC 3.1 Type AttributesGCC 3.0.4 Function Attributes Variable Attributes Type AttributesGCC 2.95.3 Function Attributes Variable Attributes Type Attributes参考: http://blog.sina.com.cn/s/blog_4c3be70100i8ii.html http://hi.baidu.com/srbadxecnihqtue/item/039535e051a0d30f8d3ea8b1http://www.cnblogs.com/respawn/archive/2012/07/09/2582078.htmlhttp://qq1587043.blog.51cto.com/261469/187562http://my.oschina.net/u/174242/blog/72760 http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Type-Attributes.html#Type-Attributeshttp://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributeshttp://www.unixwiz.net/techtips/gnu-c-attributes.html 分类: C/C++
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- 99spj.com 版权所有 湘ICP备2022005869号-5
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务