GNU C 的一大特點就是__attribute__ 機制。__attribute__ 能夠設置函數屬性(Function Attribute )、變量屬性(Variable Attribute )和類型屬性(Type Attribute )。html
__attribute__ 書寫特徵是:__attribute__ 先後都有兩個下劃線,並切後面會緊跟一對原括弧,括弧裏面是相應的__attribute__ 參數。linux
__attribute__ 語法格式爲:__attribute__ ((attribute-list))express
其位置約束爲:放於聲明的尾部「 ;」 以前。數組
關鍵字__attribute__ 也能夠對結構體(struct )或共用體(union )進行屬性設置。大體有六個參數值能夠被設定,即:aligned, packed, transparent_union, unused, deprecated 和 may_alias 。網絡
在使用__attribute__ 參數時,你也能夠在參數的先後都加上「__」 (兩個下劃線),例如,使用__aligned__而不是aligned ,這樣,你就能夠在相應的頭文件裏使用它而不用關心頭文件裏是否有重名的宏定義。數據結構
aligned (alignment)架構
該屬性設定一個指定大小的對齊格式(以字節 爲單位),例如:app
struct S {ide
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)
函數屬性能夠幫助開發者把一些特性添加到函數聲明中,從而可使編譯器在錯誤檢查方面的功能更強大。__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.c attribute後,則並不會輸出任何警告信息。
注意,默認狀況下,編譯器是能識別相似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.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, ...){ /* 函數定義 */}
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 in conjunction 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, you could 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 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.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes
下面來看一個不同的HelloWorld程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include <stdio.h>
#include <stdlib.h>
static
__attribute__((constructor))
void
before()
{
printf
(
"Hello"
);
}
static
__attribute__((destructor))
void
after()
{
printf
(
" World!\n"
);
}
int
main(
int
args,
char
** argv)
{
return
EXIT_SUCCESS;
}
|
咱們知道這是一個HelloWorld程序,因此輸出的結果就是"Hello World!",很簡單,不須要對這點過多關心.
下面咱們來關心關心別的:
1
2
3
|
__attribute__((constructor))
__attribute__((destructor))
|
解釋一下:__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))"
網絡通訊一般分爲基於數據結構的和基於流的。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字節。
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 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).
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:
/* 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.
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:
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!
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:
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.
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:
/* 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.
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.
/* 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 */ }
We'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.gnu.org:
參考:
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.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-Attributes
http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes