GNU C?的一大特色就是__attribute__機(jī)制。__attribute__可以設(shè)置函數(shù)屬性(Function Attribute)锌云、變量屬性(Variable Attribute)和類型屬性(Type Attribute)。
__attribute__書寫特征是:__attribute__前后都有兩個下劃線饼记,并切后面會緊跟一對原括弧晦溪,括弧里面是相應(yīng)的__attribute__參數(shù)夭拌。
__attribute__語法格式為:__attribute__ ((attribute-list))
其位置約束為:放于聲明的尾部“规阀;”之前恒序。
關(guān)鍵字__attribute__也可以對結(jié)構(gòu)體(struct)或共用體(union)進(jìn)行屬性設(shè)置。大致有六個參數(shù)值可以被設(shè)定谁撼,即:aligned, packed, transparent_union, unused, deprecated和may_alias歧胁。
在使用__attribute__參數(shù)時,你也可以在參數(shù)的前后都加上“__”(兩個下劃線)厉碟,例如喊巍,使用__aligned__而不是aligned,這樣墨榄,你就可以在相應(yīng)的頭文件里使用它而不用關(guān)心頭文件里是否有重名的宏定義玄糟。
aligned (alignment)
該屬性設(shè)定一個指定大小的對齊格式(以字節(jié) 為單位)勿她,例如:
struct S {
short b[3];
} __attribute__ ((aligned (8)));
typedef int int32_t __attribute__ ((aligned (8)));
該聲明將強(qiáng)制編譯器確保(盡它所能)變量類 型為struct S或者int32_t的變量在分配空間時采用8字節(jié)對齊方式袄秩。
如上所述,你可以手動指定對齊的格式,同 樣之剧,你也可以使用默認(rèn)的對齊方式郭卫。如果aligned后面不緊跟一個指定的數(shù)字值,那么編譯器將依據(jù)你的目標(biāo)機(jī)器情況使用最大最有益的對齊方式背稼。例如:
struct S {
short b[3];
} __attribute__ ((aligned));
這里贰军,如果sizeof(short)的大小為2(byte),那么蟹肘,S的大小就為6词疼。取一個2的次方值,使得該值大于等于6帘腹,則該值為8贰盗,所以編譯器將設(shè)置S類型的對齊方式為8字節(jié)。
aligned屬性使被設(shè)置的對象占用更多的空間阳欲,相反的舵盈,使用packed可以減小對象占用的空間。
需要注意的是球化,attribute屬性的效力與你的連接器也有關(guān)秽晚,如果你的連接器最大只支持16字節(jié)對齊,那么你此時定義32字節(jié)對齊也是無濟(jì)于事的筒愚。
packed
?使用該屬性對struct或者union類型進(jìn)行定義赴蝇,設(shè)定其類型的每一個變量的內(nèi)存約束。當(dāng)用在enum類型 定義時锨能,暗示了應(yīng)該使用最小完整的類型(it indicates that the smallest integral type should be used)扯再。
?下面的例子中,packed_struct類型的變量數(shù)組中的值將會緊緊的靠在一起址遇,但內(nèi)部的成員變量s不會被“pack”熄阻,如果希望內(nèi)部的成員變量也被packed的話,unpacked-struct也需要使用packed進(jìn)行相應(yīng)的約束倔约。
struct unpacked_struct
{
??????char c;
??????int i;
};
struct packed_struct
{
?????char c;
?????int??i;
?????struct unpacked_struct s;
}__attribute__ ((__packed__));
下面的例子中使用__attribute__屬性定義了一些結(jié)構(gòu)體及其變量秃殉,并給出了輸出結(jié)果和對結(jié)果的分析。
程序代 碼為:
char b;
short c;
}oo;
struct x
{
int a;
char b;
struct p px;
short c;
}__attribute__((aligned(8))) xx;
int main()
{
printf("sizeof(int)=%d,sizeof(short)=%d.sizeof(char)=%d\n",sizeof(int),sizeof(short),sizeof(char));
printf("pp=%d,mm=%d \n", sizeof(pp),sizeof(mm));
printf("oo=%d,xx=%d \n", sizeof(oo),sizeof(xx));
return 0;
}
輸出結(jié) 果:
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個字節(jié)填充浸剩,但是b是4個字節(jié)钾军,所以a占用4字節(jié),b占用4個字節(jié)绢要,而c又要占用4個字節(jié)吏恭。所以sizeof(mm)=12
sizeof(oo):
sizeof(a)+sizeof(b)+sizeof(c)=4+1+2=7
因為默 認(rèn)是以4字節(jié)對齊,所以sizeof(oo)=8
sizeof(xx):
sizeof(a)+ sizeof(b)=4+1=5
sizeof(pp)=8;即xx是采用8字節(jié)對齊的重罪,所以要在a樱哼,b后面添3個空余字節(jié)哀九,然后才能存儲px,
4+1+(3)+8+1=17
因為xx采用的對齊是8字節(jié)對齊搅幅,所以xx的大小必定是8的整數(shù)倍阅束,即xx的大小是一個比17大又是8的倍數(shù)的一個最小值,由此得到
17<24茄唐,所以sizeof(xx)=24
函數(shù)屬性(Function Attribute)
函數(shù)屬性可以幫助開發(fā)者把一些特性添加到函數(shù)聲明中息裸,從而可以使編譯器在錯誤檢查方面的功能更強(qiáng)大。__attribute__機(jī)制也很容易同非GNU應(yīng)用程序做到兼容之功效沪编。
GNU CC需要使用 –Wall編譯器來擊活該功能呼盆,這是控制警告信息的一個很好的方式。下面介紹幾個常見的屬性參數(shù)蚁廓。
__attribute__ format
該__attribute__屬性可以給被聲明的函數(shù)加上類似printf或者scanf的特征宿亡,它可以使編譯器檢查函數(shù)聲明和函數(shù)實際調(diào)用參數(shù)之間的格式化字符串是否匹配。該功能十分有用纳令,尤其是處理一些很難發(fā)現(xiàn)的bug挽荠。
format的語法格式為:
format (archetype, string-index, first-to-check)
????????? format屬性告訴編譯器,按照printf, scanf,?
strftime或strfmon的參數(shù)表格式規(guī)則對該函數(shù)的參數(shù)進(jìn)行檢查平绩∪Υ遥“archetype”指定是哪種風(fēng)格;“string-index”指定傳入函數(shù)的第幾個參數(shù)是格式化字符串捏雌;“first-to-check”指定從函數(shù)的第幾個參數(shù)開始按上述規(guī)則進(jìn)行檢查跃赚。
具體使用格式如下:
__attribute__((format(printf,m,n)))
__attribute__((format(scanf,m,n)))
其中參數(shù)m與n的含義為:
m:第幾個參數(shù)為格式化字符串(format string);
n:參數(shù)集合中的第一個性湿,即參數(shù)“…”里的第一個參數(shù)在函數(shù)參數(shù)總數(shù)排在第幾纬傲,注意,有時函數(shù)參數(shù)里還有“隱身”的呢肤频,后面會提到叹括;
在使用上,__attribute__((format(printf,m,n)))是常用的宵荒,而另一種卻很少見到汁雷。下面舉例說明,其中myprint為自己定義的一個帶有可變參數(shù)的函數(shù)报咳,其功能類似于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是一個函數(shù)的成員函數(shù),那么m和n的值可有點“懸乎”了岩臣,例如:
//m=3溜嗜;n=4
extern void myprint(int l柴底,const char *format,...)?
__attribute__((format(printf,3,4)));
其原因是,類成員函數(shù)的第一個參數(shù)實際上一個“隱身”的“this”指針粱胜。(有點C++基礎(chǔ)的都知道點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:}
運(yùn)行$gcc –Wall –c attribute.c attribute后,輸出結(jié)果為:
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中的函數(shù)聲明去掉__attribute__((format(printf,1,2)))抑钟,再重新編譯涯曲,既運(yùn)行$gcc –Wall –c attribute.c attribute后,則并不會輸出任何警告信息在塔。
注意幻件,默認(rèn)情況下,編譯器是能識別類似printf的“標(biāo)準(zhǔn)”庫函數(shù)蛔溃。
__attribute__ noreturn
該屬性通知編譯器函數(shù)從不返回值绰沥,當(dāng)遇到類似函數(shù)需要返回值而卻不可能運(yùn)行到返回值處就已經(jīng)退出來的情況,該屬性可以避免出現(xiàn)錯誤信息贺待。C庫函數(shù)中的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();
? ? ? ? ? ? ? ? /* 程序不可能到達(dá)這里*/
? ? ? ? ? }
? ? ? ? ? else
? ? ? ? ? ? ? ? ? return 0;
}
編譯顯示的輸出信息為:
$gcc –Wall –c noreturn.c
noreturn.c: In function `test':
noreturn.c:12: warning: control reaches end of non-void function
警告信息也很好理解秃臣,因為你定義了一個有返回值的函數(shù)test卻有可能沒有返回值,程序當(dāng)然不知道怎么辦了哪工!
加上__attribute__((noreturn))則可以很好的處理類似這種問題奥此。把
extern void myexit();修改為:
extern void myexit() __attribute__((noreturn));之后,編譯不會再出現(xiàn)警告信息雁比。
__attribute__ const
該屬性只能用于帶有數(shù)值類型參數(shù)的函數(shù)上稚虎。當(dāng)重復(fù)調(diào)用帶有數(shù)值參數(shù)的函數(shù)時,由于返回值是相同的偎捎,所以此時編譯器可以進(jìn)行優(yōu)化處理祥绞,除第一次需要運(yùn)算外,
其它只需要返回第一次的結(jié)果就可以了鸭限,進(jìn)而可以提高效率蜕径。該屬性主要適用于沒有靜態(tài)狀態(tài)(static
state)和副作用的一些函數(shù),并且返回值僅僅依賴輸入的參數(shù)败京。
為了說明問題兜喻,下面舉個非常“糟糕”的例子赡麦,該例子將重復(fù)調(diào)用一個帶有相同參數(shù)值的函數(shù)朴皆,具體如下:
extern
int square(int n) __attribute__???? ((const));...????????????????? for
(i = 0; i < 100; i++ )????????????????? {?????? total += square (5) +
i;???????????? }?
通過添加__attribute__((const))聲明帕识,編譯器只調(diào)用了函數(shù)一次,以后只是直接得到了相同的一個返回值遂铡。
事實上肮疗,const參數(shù)不能用在帶有指針類型參數(shù)的函數(shù)中,因為該屬性不但影響函數(shù)的參數(shù)值扒接,同樣也影響到了參數(shù)指向的數(shù)據(jù)伪货,它可能會對代碼本身產(chǎn)生嚴(yán)重甚至是不可恢復(fù)的嚴(yán)重后果。
并且钾怔,帶有該屬性的函數(shù)不能有任何副作用或者是靜態(tài)的狀態(tài)碱呼,所以,類似getchar()或time()的函數(shù)是不適合使用該屬性的宗侦。
-finstrument-functions
該參數(shù)可以使程序在編譯時愚臀,在函數(shù)的入口和出口處生成instrumentation調(diào)用。恰好在函數(shù)入口之后并恰好在函數(shù)出口之前矾利,將使用當(dāng)前函數(shù)的地址和調(diào)用地址來調(diào)用下面的
profiling?
函數(shù)姑裂。(在一些平臺上,__builtin_return_address不能在超過當(dāng)前函數(shù)范圍之外正常工作男旗,所以調(diào)用地址信息可能對profiling函數(shù)是無效的炭分。)
void __cyg_profile_func_enter(void *this_fn, void *call_site);
void __cyg_profile_func_exit(void *this_fn, void *call_site);
其中,第一個參數(shù)this_fn是當(dāng)前函數(shù)的起始地址剑肯,可在符號表中找到捧毛;第二個參數(shù)call_site是指調(diào)用處地址。
instrumentation?
也可用于在其它函數(shù)中展開的內(nèi)聯(lián)函數(shù)让网。從概念上來說呀忧,profiling調(diào)用將指出在哪里進(jìn)入和退出內(nèi)聯(lián)函數(shù)。這就意味著這種函數(shù)必須具有可尋址形式溃睹。如 果函數(shù)包含內(nèi)聯(lián)而账,而所有使用到該函數(shù)的程序都要把該內(nèi)聯(lián)展開,這會額外地增加代碼長度因篇。如果要在C 代碼中使用extern inline聲明泞辐,必須提供這種函數(shù)的可尋址形式。
可對函數(shù)指定no_instrument_function屬性竞滓,在這種情況下不會進(jìn)行
Instrumentation操作咐吼。例如,可以在以下情況下使用no_instrument_function屬性:上面列出的profiling函
數(shù)商佑、高優(yōu)先級的中斷例程以及任何不能保證profiling正常調(diào)用的函數(shù)锯茄。
no_instrument_function
如果使用了-finstrument-functions?
,將在絕大多數(shù)用戶編譯的函數(shù)的入口和出口點調(diào)用profiling函數(shù)。使用該屬性肌幽,將不進(jìn)行instrument操作晚碾。
constructor/destructor
若函數(shù)被設(shè)定為constructor屬性,則該函數(shù)會在main()函數(shù)執(zhí)行之前被自動的執(zhí)行喂急。類似的格嘁,若函數(shù)被設(shè)定為destructor屬性,則該
函數(shù)會在main()函數(shù)執(zhí)行之后或者exit()被調(diào)用后被自動的執(zhí)行廊移。擁有此類屬性的函數(shù)經(jīng)常隱式的用在程序的初始化數(shù)據(jù)方面糕簿。
這兩個屬性還沒有在面向?qū)ο驝中實現(xiàn)。
同時使用多個屬性
可以在同一個函數(shù)聲明里使用多個__attribute__画机,并且實際應(yīng)用中這種情況是十分常見的。使用方式上新症,你可以選擇兩個單獨的__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))); 如果帶有該屬性的自定義函數(shù)追加到庫的頭文件里徒爹,那么所以調(diào)用該函數(shù)的程序都要做相應(yīng)的檢查荚醒。
和非GNU編譯器的兼容性
慶幸的是,__attribute__設(shè)計的非常巧妙隆嗅,很容易作到和其它編譯器保持兼容界阁,也就是說,如果工作在其它的非GNU編譯器上胖喳,可以很容易的忽略該屬性泡躯。即使__attribute__使用了多個參數(shù),也可以很容易的使用一對圓括弧進(jìn)行處理丽焊,例如:
/* 如果使用的是非GNU C, 那么就忽略__attribute__ */#ifndef __GNUC__#???? define???? __attribute__(x)???? /*NOTHING*/#endif?
需要說明的是较剃,__attribute__適用于函數(shù)的聲明而不是函數(shù)的定義。所以技健,當(dāng)需要使用該屬性的函數(shù)時写穴,必須在同一個文件里進(jìn)行聲明,例如:
/*
函數(shù)聲明 */void die(const char *format, ...)
__attribute__((noreturn))????????????????????????????????????
__attribute__((format(printf,1,2))); void die(const char *format,
...){????????????????? /* 函數(shù)定義 */}
Specifying Attributes of Variables
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 variablexon a 16-byte boundary. On a 68040, this could be used in conjunction with anasmexpression to access themove16instruction which requires 16-byte aligned operands.
You can also specify the alignment of structure fields. For example, to create a double-word alignedintpair, you could write:
? ? ? ? ? struct foo { int x[2] __attribute__ ((aligned (8))); };
This is an alternative to creating a union with adoublemember 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程序:
#include
#include
static__attribute__((constructor)) voidbefore()
{
????printf("Hello");
}
static__attribute__((destructor)) voidafter()
{
????printf(" World!\n");
}
intmain(intargs,char** argv)
{
????returnEXIT_SUCCESS;
}
我們知道這是一個HelloWorld程序雌贱,所以輸出的結(jié)果就是"Hello World!"啊送,很簡單,不需要對這點過多關(guān)心.
下面我們來關(guān)心關(guān)心別的:
__attribute__((constructor))
__attribute__((destructor))
解釋一下:__attribute__((constructor)) 在main() 之前執(zhí)行,__attribute__((destructor)) 在main()執(zhí)行結(jié)束之后執(zhí)行.
上面的例子中我沒有在main函數(shù)中添加任何的輸出欣孤,所以看不到具體的信息.這點可以自己嘗試~
如果要在main()之前或者是執(zhí)行完成之后馋没,需要執(zhí)行很多的前處理動作或者是后處理動作,我們應(yīng)該怎么處理?
也許降传,你需要下面這些東西:
__attribute__((constructor(PRIORITY)))
__attribute__((destructor(PRIORITY)))
PRIORITY: 優(yōu)先級.
好吧披泪,下面就來試試:
執(zhí)行的輸出如下:
?從輸出的信息看,前處理都是按照優(yōu)先級先后執(zhí)行的搬瑰,而后處理則是相反的款票,好吧控硼,我們使用GDB調(diào)試驗證一下:
?從調(diào)試的信息也是驗證了上面的結(jié)果.
另外一個問題,優(yōu)先級有沒有范圍的艾少?
其實剛開始我寫的程序中的優(yōu)先級是1,我們將上面的程序改一下卡乾,然后編譯看一下會有什么樣的結(jié)果:
?0-100(包括100),是內(nèi)部保留的,所以在編碼的時候需要注意.
關(guān)于__attribute__的用法缚够,可以有另外一種寫法幔妨,先聲明函數(shù),然后再定義.
?glibc多采用第一種寫法.
關(guān)于linux內(nèi)核中的"__attribute__ ((packed))"
引用:
__attrubte__ ((packed)) 的作用就是告訴編譯器取消結(jié)構(gòu)在編譯過程中的優(yōu)化對齊,按照實際占用字節(jié)數(shù)進(jìn)行對齊谍椅。
#define __u8??? unsigned char
#define __u16?? unsigned short
/* __attribute__ ((packed)) 的位置約束是放于聲明的尾部“误堡;”之前 */
struct str_struct{
__u8??? a;
__u8??? b;
__u8??? c;
__u16?? d;
} __attribute__ ((packed));
/*? 當(dāng)用到typedef時,要特別注意__attribute__ ((packed))放置的位置雏吭,相當(dāng)于:
*? typedef struct str_stuct str;
*? 而struct str_struct 就是上面的那個結(jié)構(gòu)锁施。
*/
typedef struct {
__u8??? a;
__u8??? b;
__u8??? c;
__u16?? d;
} __attribute__ ((packed)) str;
/* 在下面這個typedef結(jié)構(gòu)中,__attribute__ ((packed))放在結(jié)構(gòu)名str_temp之后杖们,其作用是被忽略的悉抵,注意與結(jié)構(gòu)str的區(qū)別。*/
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;
}
編譯運(yùn)行:
引用:
[root@localhost root]# ./packedtest
sizeof str = 5
sizeof str_struct = 5
sizeof str_temp = 6
sizeof str_nopacked = 6
GNU C的一大特色就是__attribute__機(jī)制摘完。__attribute__可以設(shè)置函數(shù)屬性(Function Attribute)姥饰、變量屬性(Variable Attribute)和類型屬性(Type Attribute)。
__attribute__書寫特征是:__attribute__前后都有兩個下劃線孝治,并且后面會緊跟一對括弧列粪,括弧里面是相應(yīng)的__attribute__參數(shù)。
__attribute__語法格式為:
__attribute__ ((attribute-list))
其位置約束:放于聲明的尾部“谈飒;”之前篱竭。
函數(shù)屬性(Function Attribute):函數(shù)屬性可以幫助開發(fā)者把一些特性添加到函數(shù)聲明中,從而可以使編譯器在錯誤檢查方面的功能更強(qiáng)大步绸。__attribute__機(jī)制也很容易同非GNU應(yīng)用程序做到兼容之功效掺逼。
GNU CC需要使用 –Wall編譯器來擊活該功能,這是控制警告信息的一個很好的方式瓤介。
packed屬性:使用該屬性可以使得變量或者結(jié)構(gòu)體成員使用最小的對齊方式吕喘,即對變量是一字節(jié)對齊,對域(field)是位對齊刑桑。
網(wǎng)絡(luò)通信通常分為基于數(shù)據(jù)結(jié)構(gòu)的和基于流的氯质。HTTP協(xié)議就是后者的一個例子。
??? 有時為了提高程序的處理速度和數(shù)據(jù)處理的方便祠斧,會使用基于數(shù)據(jù)結(jié)構(gòu)的通信(不需要對流進(jìn)行解析)闻察。但是,當(dāng)需要在多平臺間進(jìn)行通信時,基于數(shù)據(jù)結(jié)構(gòu)的通信辕漂,往往要十分注意以下幾個方面:
[1] 字節(jié)序
[2] 變量長度
[3] 內(nèi)存對齊
在常見的系統(tǒng)架構(gòu)中(Linux X86呢灶,Windows),非單字節(jié)長度的變量類型钉嘹,都是低字節(jié)在前鸯乃,而在某些特定系統(tǒng)中,如Soalris
Sparc平臺跋涣,高字節(jié)在前缨睡。如果在發(fā)送數(shù)據(jù)前不進(jìn)行處理,那么由Linux X86發(fā)向Soalris
Sparc平臺的數(shù)據(jù)值陈辱,勢必會有極大的偏差奖年,進(jìn)而程序運(yùn)行過程中無法出現(xiàn)預(yù)計的正常結(jié)果,更嚴(yán)重時沛贪,會導(dǎo)致段錯誤陋守。
對于此種情況,我們往往使用同一的字節(jié)序鹏浅。在系統(tǒng)中嗅义,有ntohXXX(),
htonXXX()等函數(shù)屏歹,負(fù)責(zé)將數(shù)據(jù)在網(wǎng)絡(luò)字節(jié)序和本地字節(jié)序之間轉(zhuǎn)換隐砸。雖然每種系統(tǒng)的本地字節(jié)序不同,但是對于所有系統(tǒng)來說蝙眶,網(wǎng)絡(luò)字節(jié)序是固定的
-----高字節(jié)在前季希。所以,可以以網(wǎng)絡(luò)字節(jié)序為通信的標(biāo)準(zhǔn)幽纷,發(fā)送前式塌,數(shù)據(jù)都轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序。
??? 轉(zhuǎn)換的過程友浸,也建議使用ntohXXX(), htonXXX()等標(biāo)準(zhǔn)函數(shù)峰尝,這樣代碼可以輕松地在各平臺間進(jìn)行移植(像通信這種很少依賴系統(tǒng)API的代碼,做成通用版本是不錯的選擇)收恢。
變量的長度武学,在不同的系統(tǒng)之間會有差別,如同是Linux2.6.18的平臺伦意,在64位系統(tǒng)中火窒,指針的長度為8個字節(jié),而在32位系統(tǒng)中驮肉,指針又是4個字
節(jié)的長度---此處只是舉個例子熏矿,很少有人會將指針作為數(shù)據(jù)發(fā)送出去。下面是我整理的在64位Linux系統(tǒng)和32位Linux系統(tǒng)中,幾種常見C語言變
量的長度:
??????????????? short??? int??? long??? long long??? ptr??? time_t
32位?????????? 2???????? 4?????? 4???????????? 8?????????????? 4??????? 4
64位?????????? 2???????? 4?????? 8???????????? 8?????????????? 8??????? 8
??? 在定義通信用的結(jié)構(gòu)體時票编,應(yīng)該考慮使用定常的數(shù)據(jù)類型褪储,如uint32_t,4字節(jié)的固定長度栏妖,并且這屬于標(biāo)準(zhǔn)C庫(C99)乱豆,在各系統(tǒng)中都可使用。
內(nèi)存對齊的問題吊趾,也與系統(tǒng)是64位還是32位有關(guān)宛裕。如果你手頭有32位和64位系統(tǒng),不妨寫個簡單的程序測試一下论泛,你就會看到同一個結(jié)構(gòu)體匪补,即便使用了定
常的數(shù)據(jù)類型,在不同系統(tǒng)中的大小是不同的仿耽。對齊往往是以4字節(jié)或8字節(jié)為準(zhǔn)的色徘,只要你寫的測試程序,變量所占空間沒有對齊到4或8的倍數(shù)即可坟瓢,舉個簡單
的測試用的結(jié)構(gòu)體的例子吧:
struct student
{
??? char name[7];
??? uint32_t id;
??? char subject[5];
};
??? 在每個系統(tǒng)上看下這個結(jié)構(gòu)體的長度吧勇边。
??? 內(nèi)存對齊,往往是由編譯器來做的折联,如果你使用的是gcc粒褒,可以在定義變量時,添加__attribute__诚镰,來決定是否使用內(nèi)存對齊奕坟,或是內(nèi)存對齊到幾個字節(jié),以上面的結(jié)構(gòu)體為例:
?1)到4字節(jié)清笨,同樣可指定對齊到8字節(jié)月杉。
struct student
{
??? char name[7];
??? uint32_t id;
??? char subject[5];
} __attribute__ ((aligned(4)));?
2)不對齊,結(jié)構(gòu)體的長度抠艾,就是各個變量長度的和
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 foryearsin highly portable code with very good results.
Table of Contents
Compatibility with non-GNU compilers
Note that__attribute__spelled with two underscores before and two after, and there are alwaystwosets of parentheses surrounding the contents. There is a good reason for this - see below. Gnu CC needs to use the-Wallcompiler 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__ format
This__attribute__allows assigningprintf-like orscanf-like characteristics to the declared function, and this enables the compiler to check the format string against the parameters provided throughout the code. This isexceptionallyhelpful in tracking down hard-to-find bugs.
There are two flavors:
__attribute__((format(printf,m,n)))
__attribute__((format(scanf,m,n)))
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.c1extern void eprintf(const char *format, ...)2__attribute__((format(printf, 1, 2)));34void foo()5{6eprintf("s=%s\n", 5);/*error on this line*/78eprintf("n=%d,%d,%d\n", 1, 2);/*error on this line*/9}$cc -Wall -c test.ctest.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 -printfand the like - are already understood by the compiler by default.
__attribute__ noreturn
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 functionsabort()andexit()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.cextern void exitnow();int foo(int n){? ? ? ? if ( n > 0 ){? ? ? ? ? ? ? ? exitnow();/*control never reaches this point*/}? ? ? ? else? ? ? ? ? ? ? ? return 0;}$cc -c -Wall test1.ctest1.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.cextern void exitnow()__attribute__((noreturn));int foo(int n){? ? ? ? if ( n > 0 )? ? ? ? ? ? ? ? exitnow();? ? ? ? else? ? ? ? ? ? ? ? return 0;}$cc -c -Wall test2.cno warnings!
__attribute__ const
This attribute marks the function as consideringonlyits 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 normallymustcall thesquare()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,constcan't be used on functions that take pointers, because the function is not considering just the function parameters butalso 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 likegetchar()ortime()would behave very poorly under these circumstances.
Putting them together
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,allprograms that call this function receive this checking.
Compatibility with non-GNU?compilers
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 thetwosets 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 functiondeclarations, notdefinitions, 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 References
We'll note that there are many more attributes available, including those forvariablesandtypes, 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:
GCC 4.0
GCC 3.2
GCC 3.1
GCC 3.0.4
GCC 2.95.3
參考:
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