__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 m 14 15 { 16 17 char a; 18 19 int b; 20 21 short c; 22 23 }__attribute__((aligned(4))) mm; 24 25 struct o 26 27 { 28 29 int a; 30 31 char b; 32 33 short c; 34 35 }oo; 36 37 struct x 38 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)=1 pp=8,mm=12 oo=8,xx=24 分析: sizeof(pp): sizeof(a)+sizeof(b)+sizeof(c)=4+1+1=6<8 所以sizeof(pp)=8 sizeof(mm): sizeof(a)+sizeof(b)+sizeof(c)=1+4+2=7 但是 a 后面需要用 3 个字节填充,但是 b 是 4 个字节,所以 a 占用 4 字节, b 占用 4 个字节,而 c 又要占用 4 个字节。所以 sizeof(mm)=12 sizeof(oo): sizeof(a)+sizeof(b)+sizeof(c)=4+1+2=7 因为默 认是以4 字节对齐,所以sizeof(oo)=8 sizeof(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)
//m=1;n=2 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后,输出结果为: 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 } 编译显示的输出信息为: Specifying Attributes of Variables
int x __attribute__ ((aligned (16))) = 0; causes the compiler to allocate the global variable You can also specify the alignment of structure fields. For example, to create a double-word aligned struct foo { int x[2] __attribute__ ((aligned (8))); }; This is an alternative to creating a union with a As in the preceding examples, you can explicitly specify the alignment (in bytes) that you wish the compiler to use for a given variable or structure field. Alternatively, you can leave out the alignment factor and just ask the compiler to align a variable or field to the maximum useful alignment for the target machine you are compiling for. For example, you could write: short array[3] __attribute__ ((aligned)); for more: http://gcc./onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes
下面来看一个不一样的HelloWorld程序:
我们知道这是一个HelloWorld程序,所以输出的结果就是"Hello World!",很简单,不需要对这点过多关心. 下面我们来关心关心别的:
解释一下:__attribute__((constructor)) 在main() 之前执行,__attribute__((destructor)) 在main()执行结束之后执行. 上面的例子中我没有在main函数中添加任何的输出,所以看不到具体的信息.这点可以自己尝试~
如果要在main()之前或者是执行完成之后,需要执行很多的前处理动作或者是后处理动作,我们应该怎么处理? 也许,你需要下面这些东西:
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", sizeof(str)); printf("sizeof str_struct = %d\n", sizeof(struct str_struct)); printf("sizeof str_temp = %d\n", sizeof(str_temp)); printf("sizeof str_nopacked = %d\n", sizeof(str_nopacked)); return 0; } 编译运行: 引用: [root@localhost root]# ./packedtest sizeof str = 5 sizeof str_struct = 5 sizeof 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协议就是后者的一个例子。
One of the best (but little known) features of GNU C is the __attribute__ mechanism, which allows a developer to attach characteristics to function declarations to allow the compiler to perform more error checking. It was designed in a way to be compatible with non-GNU implementations, and we've been using this for years in highly portable code with very good results. 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 big fans of max warnings anyway).
__attribute__ formatThis __attribute__ allows assigning printf-like or scanf-like characteristics to the declared function, and this enables the compiler to check the format string against the parameters provided throughout the code. This is exceptionally helpful in tracking down hard-to-find bugs. There are two flavors:
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 see some 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", 5); /* error on this line */ 7 8 eprintf("n=%d,%d,%d\n", 1, 2); /* error on this line */ 9 } $ cc -Wall -c test.c test.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__ noreturnThis attribute tells the compiler that the function won't ever return, and this can be used to suppress errors about code 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 ever happen 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 without the __attribute__tag, the compiler issues a warning. The compiler is correct here, because it has no way of knowing 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.c test1.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.c no warnings! __attribute__ constThis attribute marks the function as considering only its numeric parameters. This is mainly intended for the compiler 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 solely determined by the inputs. In this highly-contrived example, the compiler normally must call the square() function in every loop even though we 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 considering just the function parameters but also the data the parameters point to, and it will almost certainly break the code very 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 things like getchar() or time() would behave very poorly under these circumstances. Putting them togetherMultiple __attributes__ can be strung together on a single declaration, and this is not uncommon in practice. You can 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 compilersFortunately, the __attribute__ mechanism was cleverly designed in a way to make it easy to quietly eliminate them if used on platforms other than GNU C. Superficially, __attribute__ appears to have multiple parameters (which would typically rule out using a macro), but the two sets of parentheses effectively make it a single parameter, and in 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 when defining 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 ReferencesWe'll note that there are many more attributes available, including those for variables and types, and they are not covered here: we have chosen to just touch on the high points. Those wishing more information can find it in the GNU online documentation athttp://gcc.:
参考: http://blog.sina.com.cn/s/blog_644c3be70100i8ii.html http://hi.baidu.com/srbadxecnihqtue/item/039535e051a0d30f8d3ea8b1 http://www.cnblogs.com/respawn/archive/2012/07/09/2582078.html http://qq164587043.blog.51cto.com/261469/187562 http://my.oschina.net/u/174242/blog/72760
http://gcc./onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html http://gcc./onlinedocs/gcc-4.0.0/gcc/Type-Attributes.html#Type-Attributes http://gcc./onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes http://www./techtips/gnu-c-attributes.html
分类: C/C++ |
|