GNU __attribute 详解
生活随笔
收集整理的這篇文章主要介紹了
GNU __attribute 详解
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
GNU C的一大特色(卻不被初學者所知)就是__attribute__機制。__attribute__可以設置函數屬性(Function Attribute)、變量屬性(Variable Attribute)和類型屬性(Type Attribute)。
__attribute__書寫特征是:__attribute__前后都有兩個下劃線,并切后面會緊跟一對原括弧,括弧里面是相應的__attribute__參數。
__attribute__語法格式為:__attribute__ ((attribute-list))
其位置約束為:放于聲明的尾部“;”之前。
函數屬性(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=2extern void myprint(const char *format,...)?__attribute__((format(printf,1,2)));//m=2;n=3extern void myprint(int l,const char *format,...)?__attribute__((format(printf,2,3)));
需要特別注意的是,如果myprint是一個函數的成員函數,那么m和n的值可有點“懸乎”了,例如://m=3;n=4extern 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.c attribute后,則并不會輸出任何警告信息。注意,默認情況下,編譯器是能識別類似printf的“標準”庫函數。
__attribute__ noreturn該屬性通知編譯器函數從不返回值,當遇到類似函數需要返回值而卻不可能運行到返回值處就已經退出來的情況,該屬性可以避免出現錯誤信息。C庫函數中的abort()和exit()的聲明格式就采用了這種格式,如下所示:
extern void exit(int) ? ? ?__attribute__((noreturn));extern void abort(void) __attribute__((noreturn));?
為了方便理解,大家可以參考如下的例子://name: noreturn.c ? ? ;測試__attribute__((noreturn))extern void myexit();
int test(int n){if ( n > 0 ){myexit();/* 程序不可能到達這里*/}elsereturn 0;}
編譯顯示的輸出信息為:
$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, ...){ ? ?/* 函數定義 */}?
更多的屬性含義參考:http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html?
變量屬性(Variable Attributes)關鍵字__attribute__也可以對變量(variable)或結構體成員(structure field)進行屬性設置。這里給出幾個常用的參數的解釋,更多的參數可參考本文給出的連接。
在使用__attribute__參數時,你也可以在參數的前后都加上“__”(兩個下劃線),例如,使用__aligned__而不是aligned,這樣,你就可以在相應的頭文件里使用它而不用關心頭文件里是否有重名的宏定義。
aligned(alignment)該屬性規定變量或結構體成員的最小的對齊格式,以字節為單位。例如:int x __attribute__((aligned (16))) = 0;?編譯器將以16字節(注意是字節byte不是位bit)對齊的方式分配一個變量。也可以對結構體成員變量設置該屬性,例如,創建一個雙字對齊的int對,可以這么寫:struct foo { int x[2] __attribute__((aligned (8))); };?
如上所述,你可以手動指定對齊的格式,同樣,你也可以使用默認的對齊方式。如果aligned后面不緊跟一個指定的數字值,那么編譯器將依據你的目標機器情況使用最大最
有益的對齊方式。例如:short array[3] __attribute__((aligned));?選擇針對目標機器最大的對齊方式,可以提高拷貝操作的效率。
aligned屬性使被設置的對象占用更多的空間,相反的,使用packed可以減小對象占用的空間。需要注意的是,attribute屬性的效力與你的連接器也有關,如果你的連接器最大只支持16字節對齊,那么你此時定義32字節對齊也是無濟于事的。
packed使用該屬性可以使得變量或者結構體成員使用最小的對齊方式,即對變量是一字節對齊,對域(field)是位對齊。下面的例子中,x成員變量使用了該屬性,則其值將緊放置在a的后面:struct test{ ??char a;int x[2] __attribute__ ((packed));};?
其它可選的屬性值還可以是:cleanup,common,nocommon,deprecated,mode,section,shared,tls_model,transparent_union,unused,vector_size,weak,
dllimport,dlexport等,
詳細信息可參考:http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes
類型屬性(Type Attribute)關鍵字__attribute__也可以對結構體(struct)或共用體(union)進行屬性設置。大致有六個參數值可以被設定,即:aligned, packed, transparent_union, unused, deprecated 和 may_alias。
在使用__attribute__參數時,你也可以在參數的前后都加上“__”(兩個下劃線),例如,使用__aligned__而不是aligned,這樣,你就可以在相應的頭文件里使用它而不用
關心頭文件里是否有重名的宏定義。
aligned (alignment)該屬性設定一個指定大小的對齊格式(以字節為單位),例如:struct S { short f[3]; } __attribute__ ((aligned (8)));typedef int more_aligned_int __attribute__ ((aligned (8)));
該聲明將強制編譯器確保(盡它所能)變量類型為struct S或者more-aligned-int的變量在分配空間時采用8字節對齊方式。如上所述,你可以手動指定對齊的格式,同樣,你也可以使用默認的對齊方式。如果aligned后面不緊跟一個指定的數字值,那么編譯器將依據你的目標機器情況使用最大最有益的對齊方式。例如:struct S { short f[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)。
下面的例子中,my-packed-struct類型的變量數組中的值將會緊緊的靠在一起,但內部的成員變量s不會被“pack”,如果希望內部的成員變量也被packed的話,my-unpacked-struct也需要使用packed進行相應的約束。
struct my_unpacked_struct{char c;int i;};struct my_packed_struct?{char c;int ? ? i;struct my_unpacked_struct s;}__attribute__ ((__packed__));
其它屬性的含義見:http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Type-Attributes.html#Type-Attributes
變量屬性與類型屬性舉例下面的例子中使用__attribute__屬性定義了一些結構體及其變量,并給出了輸出結果和對結果的分析。程序代碼為:
struct p{int a;char b;char c;}__attribute__((aligned(4))) pp;
struct q{int a;char b;struct n qn;char c;}__attribute__((aligned(8))) qq;
int main(){printf("sizeof(int)=%d,sizeof(short)=%d.sizeof(char)=%d\n",sizeof(int),sizeof(short),sizeof(char));printf("pp=%d,qq=%d \n", sizeof(pp),sizeof(qq));
return 0;}
輸出結果:
sizeof(int)=4,sizeof(short)=2.sizeof(char)=1pp=8,qq=24
分析:
sizeof(pp):sizeof(a)+ sizeof(b)+ sizeof(c)=4+1+1=6<23=8= sizeof(pp)sizeof(qq):sizeof(a)+ sizeof(b)=4+1=5sizeof(qn)=8;即qn是采用8字節對齊的,所以要在a,b后面添3個空余字節,然后才能存儲qn,4+1+(3)+8+1=17因為qq采用的對齊是8字節對齊,所以qq的大小必定是8的整數倍,即qq的大小是一個比17大又是8的倍數的一個最小值,由此得到17<24+8=24= sizeof(qq)
更詳細的介紹見:http://gcc.gnu.org/下面是一些便捷的連接:GCC 4.0 Function Attributes;GCC 4.0 Variable Attributes ;GCC 4.0 Type?Attributes ;GCC 3.2 Function Attributes ;GCC 3.2 Variable Attributes ;GCC 3.2?Type Attributes ;GCC 3.1 Function Attributes ;GCC 3.1 Variable Attributes?
Reference:1.有關__attribute__的相對簡單的介紹:http://www.unixwiz.net/techtips/gnu-c-attributes.html2.__attribute__詳細介紹:http://gcc.gnu.org/
__attribute__書寫特征是:__attribute__前后都有兩個下劃線,并切后面會緊跟一對原括弧,括弧里面是相應的__attribute__參數。
__attribute__語法格式為:__attribute__ ((attribute-list))
其位置約束為:放于聲明的尾部“;”之前。
函數屬性(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=2extern void myprint(const char *format,...)?__attribute__((format(printf,1,2)));//m=2;n=3extern void myprint(int l,const char *format,...)?__attribute__((format(printf,2,3)));
需要特別注意的是,如果myprint是一個函數的成員函數,那么m和n的值可有點“懸乎”了,例如://m=3;n=4extern 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.c attribute后,則并不會輸出任何警告信息。注意,默認情況下,編譯器是能識別類似printf的“標準”庫函數。
__attribute__ noreturn該屬性通知編譯器函數從不返回值,當遇到類似函數需要返回值而卻不可能運行到返回值處就已經退出來的情況,該屬性可以避免出現錯誤信息。C庫函數中的abort()和exit()的聲明格式就采用了這種格式,如下所示:
extern void exit(int) ? ? ?__attribute__((noreturn));extern void abort(void) __attribute__((noreturn));?
為了方便理解,大家可以參考如下的例子://name: noreturn.c ? ? ;測試__attribute__((noreturn))extern void myexit();
int test(int n){if ( n > 0 ){myexit();/* 程序不可能到達這里*/}elsereturn 0;}
編譯顯示的輸出信息為:
$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, ...){ ? ?/* 函數定義 */}?
更多的屬性含義參考:http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html?
變量屬性(Variable Attributes)關鍵字__attribute__也可以對變量(variable)或結構體成員(structure field)進行屬性設置。這里給出幾個常用的參數的解釋,更多的參數可參考本文給出的連接。
在使用__attribute__參數時,你也可以在參數的前后都加上“__”(兩個下劃線),例如,使用__aligned__而不是aligned,這樣,你就可以在相應的頭文件里使用它而不用關心頭文件里是否有重名的宏定義。
aligned(alignment)該屬性規定變量或結構體成員的最小的對齊格式,以字節為單位。例如:int x __attribute__((aligned (16))) = 0;?編譯器將以16字節(注意是字節byte不是位bit)對齊的方式分配一個變量。也可以對結構體成員變量設置該屬性,例如,創建一個雙字對齊的int對,可以這么寫:struct foo { int x[2] __attribute__((aligned (8))); };?
如上所述,你可以手動指定對齊的格式,同樣,你也可以使用默認的對齊方式。如果aligned后面不緊跟一個指定的數字值,那么編譯器將依據你的目標機器情況使用最大最
有益的對齊方式。例如:short array[3] __attribute__((aligned));?選擇針對目標機器最大的對齊方式,可以提高拷貝操作的效率。
aligned屬性使被設置的對象占用更多的空間,相反的,使用packed可以減小對象占用的空間。需要注意的是,attribute屬性的效力與你的連接器也有關,如果你的連接器最大只支持16字節對齊,那么你此時定義32字節對齊也是無濟于事的。
packed使用該屬性可以使得變量或者結構體成員使用最小的對齊方式,即對變量是一字節對齊,對域(field)是位對齊。下面的例子中,x成員變量使用了該屬性,則其值將緊放置在a的后面:struct test{ ??char a;int x[2] __attribute__ ((packed));};?
其它可選的屬性值還可以是:cleanup,common,nocommon,deprecated,mode,section,shared,tls_model,transparent_union,unused,vector_size,weak,
dllimport,dlexport等,
詳細信息可參考:http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes
類型屬性(Type Attribute)關鍵字__attribute__也可以對結構體(struct)或共用體(union)進行屬性設置。大致有六個參數值可以被設定,即:aligned, packed, transparent_union, unused, deprecated 和 may_alias。
在使用__attribute__參數時,你也可以在參數的前后都加上“__”(兩個下劃線),例如,使用__aligned__而不是aligned,這樣,你就可以在相應的頭文件里使用它而不用
關心頭文件里是否有重名的宏定義。
aligned (alignment)該屬性設定一個指定大小的對齊格式(以字節為單位),例如:struct S { short f[3]; } __attribute__ ((aligned (8)));typedef int more_aligned_int __attribute__ ((aligned (8)));
該聲明將強制編譯器確保(盡它所能)變量類型為struct S或者more-aligned-int的變量在分配空間時采用8字節對齊方式。如上所述,你可以手動指定對齊的格式,同樣,你也可以使用默認的對齊方式。如果aligned后面不緊跟一個指定的數字值,那么編譯器將依據你的目標機器情況使用最大最有益的對齊方式。例如:struct S { short f[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)。
下面的例子中,my-packed-struct類型的變量數組中的值將會緊緊的靠在一起,但內部的成員變量s不會被“pack”,如果希望內部的成員變量也被packed的話,my-unpacked-struct也需要使用packed進行相應的約束。
struct my_unpacked_struct{char c;int i;};struct my_packed_struct?{char c;int ? ? i;struct my_unpacked_struct s;}__attribute__ ((__packed__));
其它屬性的含義見:http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Type-Attributes.html#Type-Attributes
變量屬性與類型屬性舉例下面的例子中使用__attribute__屬性定義了一些結構體及其變量,并給出了輸出結果和對結果的分析。程序代碼為:
struct p{int a;char b;char c;}__attribute__((aligned(4))) pp;
struct q{int a;char b;struct n qn;char c;}__attribute__((aligned(8))) qq;
int main(){printf("sizeof(int)=%d,sizeof(short)=%d.sizeof(char)=%d\n",sizeof(int),sizeof(short),sizeof(char));printf("pp=%d,qq=%d \n", sizeof(pp),sizeof(qq));
return 0;}
輸出結果:
sizeof(int)=4,sizeof(short)=2.sizeof(char)=1pp=8,qq=24
分析:
sizeof(pp):sizeof(a)+ sizeof(b)+ sizeof(c)=4+1+1=6<23=8= sizeof(pp)sizeof(qq):sizeof(a)+ sizeof(b)=4+1=5sizeof(qn)=8;即qn是采用8字節對齊的,所以要在a,b后面添3個空余字節,然后才能存儲qn,4+1+(3)+8+1=17因為qq采用的對齊是8字節對齊,所以qq的大小必定是8的整數倍,即qq的大小是一個比17大又是8的倍數的一個最小值,由此得到17<24+8=24= sizeof(qq)
更詳細的介紹見:http://gcc.gnu.org/下面是一些便捷的連接:GCC 4.0 Function Attributes;GCC 4.0 Variable Attributes ;GCC 4.0 Type?Attributes ;GCC 3.2 Function Attributes ;GCC 3.2 Variable Attributes ;GCC 3.2?Type Attributes ;GCC 3.1 Function Attributes ;GCC 3.1 Variable Attributes?
Reference:1.有關__attribute__的相對簡單的介紹:http://www.unixwiz.net/techtips/gnu-c-attributes.html2.__attribute__詳細介紹:http://gcc.gnu.org/
總結
以上是生活随笔為你收集整理的GNU __attribute 详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个QQ空间的钓鱼盗号过程揭露,大家谨防
- 下一篇: 用热水壶煮鸡蛋安全吗