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 該屬性可以給被聲明的函數加上類似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:參數集合中的第一個,即參數“…”里的第一個參數在函數參數總數排在第幾.這里需要注意,有時函數參數里還有“隱身”的,如C++的類成員函數的第一個參數實際上是"隱身"的"this"指針;
在使用上,__attribute__((format(printf,m,n)))是常用的,而另一種卻很少見到。
下面舉例說明,其中myprint為自己定義的一個帶有可變參數的函數,其功能類似於printf:
// m = 1, n = 2...如果在這里myprint()為類成員函數,則gcc編譯后會提示"format argument is not a pointer"的警告 extern void myprint(const char *format,...) __attribute__((format(printf,1,2))); // m = 2, n = 3 extern void myprint(short num,const char *format,...) __attribute__((format(printf,2,3)));
最經典的應用可以去看linux源碼里的函數device_create(...)和class_device_create(...), 做linux驅動開發的小伙伴應該對這兩個函數不陌生.
__attribute__ noreturn 該屬性通知編譯器函數從不返回值。當遇到函數需要返回值卻還沒運行到返回值處就已退出來的情況,該屬性可以避免出現錯誤信息。
C庫函數中的abort()和exit()的聲明格式就采用了這種格式:
extern void myexit(int);
int testFunc(void) { printf("-- Enter %s --", __func__); myexit(0); // 其實函數運行不到這里 printf("-- Exit %s --", __func__); } void myexit(int i) { exit(i); }
__attribute__ constructor/destructor 若函數被設定為constructor屬性,則該函數會在 main()函數執行之前被自動的執行。類似的,若函數被設定為destructor屬性,則該函數會在main()函數執行之后或者exit()被調用后被自動的執行。擁有此類屬性的函數經常隱式的用在程序的初始化數據方面。
這兩個屬性還沒有在面向對象C中實現。
__attribute__((constructor)) void before_main() { printf("--- %s\n", __func__); } __attribute__((destructor)) void after_main() { printf("--- %s\n", __func__); } int main(int argc, char **argv) { printf("--- %s\n", __func__); exit(0); printf("--- %s, exit ?\n", __func__); return 0; }
執行結果為:
--- before_main --- main --- after_main