天天看點

__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES

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 後面不緊跟一個指定的數字值,那麼編譯器将依據你的目标機器情況使用最大最有益的對齊方式。例如:

} __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__ 屬性定義了一些結構體及其變量,并給出了輸出結果和對結果的分析。

程式代 碼為:

__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES
__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES

輸出結 果:

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)

函數屬性可以幫助開發者把一些特性添加到函數聲明中,進而可以使編譯器在錯誤檢查方面的功能更強大。__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

__attribute__((format(printf,3,4)));

其原因是,類成員函數的第一個參數實際上一個“隐身”的“this”指針。(有點C++基礎的都知道點this指針,不知道你在這裡還知道嗎?)

這裡給出測試用例:attribute.c,代碼如下:

__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES
__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES

運作$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)); 為了友善了解,大家可以參考如下的例子:

__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES
__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES

編譯顯示的輸出資訊為:

$gcc –Wall –c noreturn.c

noreturn.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, ...){                  /* 函數定義 */}

<code>aligned (</code>alignment<code>)</code>This attribute specifies a minimum alignment for the variable or structure field, measured in bytes. For example, the declaration:

causes the compiler to allocate the global variable <code>x</code> on a 16-byte boundary. On a 68040, this could be used in conjunction with an <code>asm</code> expression to access the<code>move16</code> instruction which requires 16-byte aligned operands.

You can also specify the alignment of structure fields. For example, to create a double-word aligned <code>int</code> pair, you could write:

This is an alternative to creating a union with a <code>double</code> 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 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:

下面來看一個不一樣的HelloWorld程式:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<code>#include &lt;stdio.h&gt;</code>

<code>#include &lt;stdlib.h&gt;</code>

<code>static</code>  <code>__attribute__((constructor))</code><code>void</code> <code>before()</code>

<code>{</code>

<code>    </code><code>printf</code><code>(</code><code>"Hello"</code><code>);</code>

<code>}</code>

<code>static</code>  <code>__attribute__((destructor))</code><code>void</code> <code>after()</code>

<code>    </code><code>printf</code><code>(</code><code>" World!\n"</code><code>);</code>

<code>int</code> <code>main(</code><code>int</code> <code>args,</code><code>char</code> <code>** argv)</code>

<code>    </code><code>return</code> <code>EXIT_SUCCESS;</code>

 我們知道這是一個HelloWorld程式,是以輸出的結果就是"Hello World!",很簡單,不需要對這點過多關心.

下面我們來關心關心别的:

<code>__attribute__((constructor))</code>

<code>__attribute__((destructor))</code>

 解釋一下:__attribute__((constructor)) 在main() 之前執行,__attribute__((destructor)) 在main()執行結束之後執行.

上面的例子中我沒有在main函數中添加任何的輸出,是以看不到具體的資訊.這點可以自己嘗試~

如果要在main()之前或者是執行完成之後,需要執行很多的前處理動作或者是後處理動作,我們應該怎麼處理?

也許,你需要下面這些東西:

<code>__attribute__((constructor(PRIORITY)))</code>

<code>__attribute__((destructor(PRIORITY)))</code>

 PRIORITY: 優先級.

好吧,下面就來試試:

__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES

執行的輸出如下:

__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES

 從輸出的資訊看,前處理都是按照優先級先後執行的,而後處理則是相反的,好吧,我們使用GDB調試驗證一下:

__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES

 從調試的資訊也是驗證了上面的結果.

另外一個問題,優先級有沒有範圍的? 

其實剛開始我寫的程式中的優先級是1,我們将上面的程式改一下,然後編譯看一下會有什麼樣的結果:

__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES
__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES

 0-100(包括100),是内部保留的,是以在編碼的時候需要注意.

關于__attribute__的用法,可以有另外一種寫法,先聲明函數,然後再定義.

__ATTRIBUTE__ 你知多少?【轉】__ATTRIBUTE__ FORMAT__ATTRIBUTE__ NORETURN__ATTRIBUTE__ CONSTPUTTING THEM TOGETHERCOMPATIBILITY WITH NON-GNU COMPILERSOTHER REFERENCES

 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 {

} __attribute__ ((packed)) str;

/* 在下面這個typedef結構中,__attribute__ ((packed))放在結構名str_temp之後,其作用是被忽略的,注意與結構str的差別。*/

}str_temp __attribute__ ((packed));

}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協定就是後者的一個例子。

    有時為了提高程式的處理速度和資料處理的友善,會使用基于資料結構的通信(不需要對流進行解析)。但是,當需要在多平台間進行通信時,基于資料結構的通信,往往要十分注意以下幾個方面:

[1] 位元組序

[2] 變量長度

[3] 記憶體對齊

    在常見的系統架構中(Linux X86,Windows),非單位元組長度的變量類型,都是低位元組在前,而在某些特定系統中,如Soalris Sparc平台,高位元組在前。如果在發送資料前不進行處理,那麼由Linux X86發向Soalris Sparc平台的資料值,勢必會有極大的偏差,進而程式運作過程中無法出現預計的正常結果,更嚴重時,會導緻段錯誤。

    對于此種情況,我們往往使用同一的位元組序。在系統中,有ntohXXX(), htonXXX()等函數,負責将資料在網絡位元組序和本地位元組序之間轉換。雖然每種系統的本地位元組序不同,但是對于所有系統來說,網絡位元組序是固定的 -----高位元組在前。是以,可以以網絡位元組序為通信的标準,發送前,資料都轉換為網絡位元組序。

    轉換的過程,也建議使用ntohXXX(), htonXXX()等标準函數,這樣代碼可以輕松地在各平台間進行移植(像通信這種很少依賴系統API的代碼,做成通用版本是不錯的選擇)。

    變量的長度,在不同的系統之間會有差别,如同是Linux2.6.18的平台,在64位系統中,指針的長度為8個位元組,而在32位系統中,指針又是4個字 節的長度---此處隻是舉個例子,很少有人會将指針作為資料發送出去。下面是我整理的在64位Linux系統和32位Linux系統中,幾種常見C語言變 量的長度:

                short    int    long    long long    ptr    time_t

32位           2         4       4             8               4        4

64位           2         4       8             8               8        8

    在定義通信用的結構體時,應該考慮使用定常的資料類型,如uint32_t,4位元組的固定長度,并且這屬于标準C庫(C99),在各系統中都可使用。

    記憶體對齊的問題,也與系統是64位還是32位有關。如果你手頭有32位和64位系統,不妨寫個簡單的程式測試一下,你就會看到同一個結構體,即便使用了定 常的資料類型,在不同系統中的大小是不同的。對齊往往是以4位元組或8位元組為準的,隻要你寫的測試程式,變量所占空間沒有對齊到4或8的倍數即可,舉個簡單 的測試用的結構體的例子吧:

struct student

    char name[7];

    uint32_t id;

    char subject[5];

    在每個系統上看下這個結構體的長度吧。

    記憶體對齊,往往是由編譯器來做的,如果你使用的是gcc,可以在定義變量時,添加__attribute__,來決定是否使用記憶體對齊,或是記憶體對齊到幾個位元組,以上面的結構體為例:

 1)到4位元組,同樣可指定對齊到8位元組。

} __attribute__ ((aligned(4))); 

2)不對齊,結構體的長度,就是各個變量長度的和

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.

Table of Contents

<a href="http://www.unixwiz.net/techtips/gnu-c-attributes.html#format">__attribute__ format</a>

<a href="http://www.unixwiz.net/techtips/gnu-c-attributes.html#noreturn">__attribute__ noreturn</a>

<a href="http://www.unixwiz.net/techtips/gnu-c-attributes.html#const">__attribute__ const</a>

<a href="http://www.unixwiz.net/techtips/gnu-c-attributes.html#together">Putting them together</a>

<a href="http://www.unixwiz.net/techtips/gnu-c-attributes.html#compat">Compatibility with non-GNU compilers</a>

<a href="http://www.unixwiz.net/techtips/gnu-c-attributes.html#refs">Other References</a>

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).

This __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:

With the functions so declared, the compiler will examine the argument lists

Note that the "standard" library functions - printf and the like - are already understood by the compiler by default.

This 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:

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.

But when we add __attribute__, the compiler suppresses the spurious warning:

This 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:

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.

Multiple __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:

If this is tucked away safely in a library header file, all programs that call this function receive this checking.

Fortunately, 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.

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):

<dl></dl>

<dt>GCC 4.0</dt>

<dd></dd>

<dt>GCC 3.2</dt>

<a href="http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Type-Attributes.html">GCC 3.2 Type Attributes</a>

<dt>GCC 3.1</dt>

<a href="http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Type-Attributes.html">GCC 3.1 Type Attributes</a>

<dt>GCC 3.0.4</dt>

<a href="http://gcc.gnu.org/onlinedocs/gcc-3.0.4/gcc_5.html#SEC102">Type Attributes</a>

<dt>GCC 2.95.3</dt>

<a href="http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html#SEC91">Type Attributes</a>

參考:

<a href="http://blog.sina.com.cn/s/blog_644c3be70100i8ii.html">http://blog.sina.com.cn/s/blog_644c3be70100i8ii.html</a>

<a href="http://hi.baidu.com/srbadxecnihqtue/item/039535e051a0d30f8d3ea8b1">http://hi.baidu.com/srbadxecnihqtue/item/039535e051a0d30f8d3ea8b1</a>

<a href="http://www.cnblogs.com/respawn/archive/2012/07/09/2582078.html">http://www.cnblogs.com/respawn/archive/2012/07/09/2582078.html</a>

<a href="http://qq164587043.blog.51cto.com/261469/187562">http://qq164587043.blog.51cto.com/261469/187562</a>

<a href="http://my.oschina.net/u/174242/blog/72760">http://my.oschina.net/u/174242/blog/72760</a>

<a href="http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html">http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html</a>

<a href="http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Type-Attributes.html#Type-Attributes">http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Type-Attributes.html#Type-Attributes</a>

<a href="http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes">http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes</a>

<a href="http://www.unixwiz.net/techtips/gnu-c-attributes.html">http://www.unixwiz.net/techtips/gnu-c-attributes.html</a>

【新浪微網誌】 張昺華--sky

【twitter】 @sky2030_

【facebook】 張昺華 zhangbinghua

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利.

繼續閱讀