<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>
"); //-->

博客專(zhuān)欄

EEPW首頁(yè) > 博客 > C之a(chǎn)ttribute用法

C之a(chǎn)ttribute用法

發(fā)布人:電子禪石 時(shí)間:2019-12-16 來(lái)源:工程師 發(fā)布文章

轉自:http://www.cnblogs.com/astwish/p/3460618.html

GNU C 的一大特色就是__attribute__ 機制。__attribute__ 可以設置函數屬性(Function Attribute )、變量屬性(Variable Attribute )和類(lèi)型屬性(Type Attribute )。

__attribute__ 書(shū)寫(xiě)特征是:__attribute__ 前后都有兩個(gè)下劃線(xiàn),并切后面會(huì )緊跟一對原括弧,括弧里面是相應的__attribute__ 參數。

__attribute__ 語(yǔ)法格式為:__attribute__ ((attribute-list))

其位置約束為:放于聲明的尾部“ ;” 之前。

 

關(guān)鍵字__attribute__ 也可以對結構體(struct )或共用體(union )進(jìn)行屬性設置。大致有六個(gè)參數值可以被設定,即:aligned, packed, transparent_union, unused, deprecated 和 may_alias 。

在使用__attribute__ 參數時(shí),你也可以在參數的前后都加上“__” (兩個(gè)下劃線(xiàn)),例如,使用__aligned__而不是aligned ,這樣,你就可以在相應的頭文件里使用它而不用關(guān)心頭文件里是否有重名的宏定義。

aligned (alignment)

該屬性設定一個(gè)指定大小的對齊格式(以字節 為單位),例如:

struct S {

short b[3];

} __attribute__ ((aligned (8)));

typedef int int32_t __attribute__ ((aligned (8)));

該聲明將強制編譯器確保(盡它所能)變量類(lèi) 型為struct S 或者int32_t 的變量在分配空間時(shí)采用8 字節對齊方式。

如上所述,你可以手動(dòng)指定對齊的格式,同 樣,你也可以使用默認的對齊方式。如果aligned 后面不緊跟一個(gè)指定的數字值,那么編譯器將依據你的目標機器情況使用最大最有益的對齊方式。例如:

struct S {

short b[3];

} __attribute__ ((aligned));

這里,如果sizeof (short )的大小為2 (byte ),那么,S 的大小就為6 。取一個(gè)2 的次方值,使得該值大于等于6 ,則該值為8 ,所以編譯器將設置S 類(lèi)型的對齊方式為8 字節。

aligned 屬性使被設置的對象占用更多的空間,相反的,使用packed 可以減小對象占用的空間。

需要注意的是,attribute 屬性的效力與你的連接器也有關(guān),如果你的連接器最大只支持16 字節對齊,那么你此時(shí)定義32 字節對齊也是無(wú)濟于事的。

packed

  使用該屬性對struct 或者union 類(lèi)型進(jìn)行定義,設定其類(lèi)型的每一個(gè)變量的內存約束。當用在enum 類(lèi)型 定義時(shí),暗示了應該使用最小完整的類(lèi)型(it indicates that the smallest integral type should be used)。

  下面的例子中,packed_struct 類(lèi)型的變量數組中的值將會(huì )緊緊的靠在一起,但內部的成員變量s 不會(huì )被“pack” ,如果希望內部的成員變量也被packed 的話(huà),unpacked-struct 也需要使用packed 進(jìn)行相應的約束。

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 個(gè)字節填充,但是 b 是 4 個(gè)字節,所以 a 占用 4 字節, b 占用 4 個(gè)字節,而 c 又要占用 4 個(gè)字節。所以 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 個(gè)空余字節,然后才能存儲px ,

4+1+ (3 )+8+1=17

因為xx 采用的對齊是8 字節對齊,所以xx 的大小必定是8 的整數倍,即xx 的大小是一個(gè)比17 大又是8 的倍數的一個(gè)最小值,由此得到

17<24 ,所以sizeof(xx)=24

函數屬性(Function Attribute)
函數屬性可以幫助開(kāi)發(fā)者把一些特性添加到函數聲明中,從而可以使編譯器在錯誤檢查方面的功能更強大。__attribute__機制也很容易同非GNU應用程序做到兼容之功效。
GNU CC需要使用 –Wall編譯器來(lái)?yè)艋钤摴δ?,這是控制警告信息的一個(gè)很好的方式。下面介紹幾個(gè)常見(jiàn)的屬性參數。
__attribute__ format
該__attribute__屬性可以給被聲明的函數加上類(lèi)似printf或者scanf的特征,它可以使編譯器檢查函數聲明和函數實(shí)際調用參數之間的格式化字符串是否匹配。該功能十分有用,尤其是處理一些很難發(fā)現的bug。
format的語(yǔ)法格式為:
format (archetype, string-index, first-to-check)
          format屬性告訴編譯器,按照printf, scanf, 
strftime或strfmon的參數表格式規則對該函數的參數進(jìn)行檢查?!癮rchetype”指定是哪種風(fēng)格;“string-index”指定傳入函數的第幾個(gè)參數是格式化字符串;“first-to-check”指定從函數的第幾個(gè)參數開(kāi)始按上述規則進(jìn)行檢查。
具體使用格式如下:
__attribute__((format(printf,m,n)))
__attribute__((format(scanf,m,n)))
其中參數m與n的含義為:
m:第幾個(gè)參數為格式化字符串(format string);
n:參數集合中的第一個(gè),即參數“…”里的第一個(gè)參數在函數參數總數排在第幾,注意,有時(shí)函數參數里還有“隱身”的呢,后面會(huì )提到;
在使用上,__attribute__((format(printf,m,n)))是常用的,而另一種卻很少見(jiàn)到。下面舉例說(shuō)明,其中myprint為自己定義的一個(gè)帶有可變參數的函數,其功能類(lèi)似于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是一個(gè)函數的成員函數,那么m和n的值可有點(diǎn)“懸乎”了,例如:
//m=3;n=4
extern void myprint(int l,const char *format,...) 
__attribute__((format(printf,3,4)));
其原因是,類(lèi)成員函數的第一個(gè)參數實(shí)際上一個(gè)“隱身”的“this”指針。(有點(diǎn)C++基礎的都知道點(diǎn)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后,則并不會(huì )輸出任何警告信息。
注意,默認情況下,編譯器是能識別類(lèi)似printf的“標準”庫函數。
__attribute__ noreturn
該屬性通知編譯器函數從不返回值,當遇到類(lèi)似函數需要返回值而卻不可能運行到返回值處就已經(jīng)退出來(lái)的情況,該屬性可以避免出現錯誤信息。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

警告信息也很好理解,因為你定義了一個(gè)有返回值的函數test卻有可能沒(méi)有返回值,程序當然不知道怎么辦了!
加上__attribute__((noreturn))則可以很好的處理類(lèi)似這種問(wèn)題。把
extern void myexit();修改為:
extern void myexit() __attribute__((noreturn));之后,編譯不會(huì )再出現警告信息。
__attribute__ const
該屬性只能用于帶有數值類(lèi)型參數的函數上。當重復調用帶有數值參數的函數時(shí),由于返回值是相同的,所以此時(shí)編譯器可以進(jìn)行優(yōu)化處理,除第一次需要運算外,  其它只需要返回第一次的結果就可以了,進(jìn)而可以提高效率。該屬性主要適用于沒(méi)有靜態(tài)狀態(tài)(static  state)和副作用的一些函數,并且返回值僅僅依賴(lài)輸入的參數。
為了說(shuō)明問(wèn)題,下面舉個(gè)非?!霸愀狻钡睦?,該例子將重復調用一個(gè)帶有相同參數值的函數,具體如下:

extern  int square(int n) __attribute__     ((const));...                  for  (i = 0; i < 100; i++ )                  {       total += square (5) +  i;             } 
通過(guò)添加__attribute__((const))聲明,編譯器只調用了函數一次,以后只是直接得到了相同的一個(gè)返回值。
事實(shí)上,const參數不能用在帶有指針類(lèi)型參數的函數中,因為該屬性不但影響函數的參數值,同樣也影響到了參數指向的數據,它可能會(huì )對代碼本身產(chǎn)生嚴重甚至是不可恢復的嚴重后果。
并且,帶有該屬性的函數不能有任何副作用或者是靜態(tài)的狀態(tài),所以,類(lèi)似getchar()或time()的函數是不適合使用該屬性的。
-finstrument-functions
該參數可以使程序在編譯時(shí),在函數的入口和出口處生成instrumentation調用。恰好在函數入口之后并恰好在函數出口之前,將使用當前函數的地址和調用地址來(lái)調用下面的
profiling 
函數。(在一些平臺上,__builtin_return_address不能在超過(guò)當前函數范圍之外正常工作,所以調用地址信息可能對profiling函數是無(wú)效的。)

void __cyg_profile_func_enter(void *this_fn, void *call_site);
void __cyg_profile_func_exit(void *this_fn, void *call_site);

其中,第一個(gè)參數this_fn是當前函數的起始地址,可在符號表中找到;第二個(gè)參數call_site是指調用處地址。
instrumentation 
也可用于在其它函數中展開(kāi)的內聯(lián)函數。從概念上來(lái)說(shuō),profiling調用將指出在哪里進(jìn)入和退出內聯(lián)函數。這就意味著(zhù)這種函數必須具有可尋址形式。如  果函數包含內聯(lián),而所有使用到該函數的程序都要把該內聯(lián)展開(kāi),這會(huì )額外地增加代碼長(cháng)度。如果要在C 代碼中使用extern  inline聲明,必須提供這種函數的可尋址形式。
可對函數指定no_instrument_function屬性,在這種情況下不會(huì )進(jìn)行  Instrumentation操作。例如,可以在以下情況下使用no_instrument_function屬性:上面列出的profiling函  數、高優(yōu)先級的中斷例程以及任何不能保證profiling正常調用的函數。
no_instrument_function
如果使用了-finstrument-functions 
,將在絕大多數用戶(hù)編譯的函數的入口和出口點(diǎn)調用profiling函數。使用該屬性,將不進(jìn)行instrument操作。
constructor/destructor
若函數被設定為constructor屬性,則該函數會(huì )在main()函數執行之前被自動(dòng)的執行。類(lèi)似的,若函數被設定為destructor屬性,則該  函數會(huì )在main()函數執行之后或者exit()被調用后被自動(dòng)的執行。擁有此類(lèi)屬性的函數經(jīng)常隱式的用在程序的初始化數據方面。
這兩個(gè)屬性還沒(méi)有在面向對象C中實(shí)現。
同時(shí)使用多個(gè)屬性
可以在同一個(gè)函數聲明里使用多個(gè)__attribute__,并且實(shí)際應用中這種情況是十分常見(jiàn)的。使用方式上,你可以選擇兩個(gè)單獨的__attribute__,或者把它們寫(xiě)在一起,可以參考下面的例子:

/*  把類(lèi)似printf的消息傳遞給stderr 并退出 */extern void die(const char *format,  ...)                  __attribute__((noreturn))                   __attribute__((format(printf, 1, 2))); 或者寫(xiě)成 extern void die(const char  *format, ...)                  __attribute__((noreturn, format(printf,  1, 2))); 如果帶有該屬性的自定義函數追加到庫的頭文件里,那么所以調用該函數的程序都要做相應的檢查。

和非GNU編譯器的兼容性
慶幸的是,__attribute__設計的非常巧妙,很容易作到和其它編譯器保持兼容,也就是說(shuō),如果工作在其它的非GNU編譯器上,可以很容易的忽略該屬性。即使__attribute__使用了多個(gè)參數,也可以很容易的使用一對圓括弧進(jìn)行處理,例如:

/* 如果使用的是非GNU C, 那么就忽略__attribute__ */#ifndef __GNUC__#     define     __attribute__(x)     /*NOTHING*/#endif 
需要說(shuō)明的是,__attribute__適用于函數的聲明而不是函數的定義。所以,當需要使用該屬性的函數時(shí),必須在同一個(gè)文件里進(jìn)行聲明,例如:

/*  函數聲明 */void die(const char *format, ...)  __attribute__((noreturn))                                      __attribute__((format(printf,1,2))); void die(const char *format,  ...){                  /* 函數定義 */}

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

 

下面來(lái)看一個(gè)不一樣的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; }  

 我們知道這是一個(gè)HelloWorld程序,所以輸出的結果就是"Hello World!",很簡(jiǎn)單,不需要對這點(diǎn)過(guò)多關(guān)心.

下面我們來(lái)關(guān)心關(guān)心別的:

1 2 3__attribute__((constructor))   __attribute__((destructor))  

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

上面的例子中我沒(méi)有在main函數中添加任何的輸出,所以看不到具體的信息.這點(diǎn)可以自己嘗試~

 

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

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

__attribute__((constructor(PRIORITY))) __attribute__((destructor(PRIORITY)))  

 PRIORITY: 優(yōu)先級.

好吧,下面就來(lái)試試:

執行的輸出如下:

 從輸出的信息看,前處理都是按照優(yōu)先級先后執行的,而后處理則是相反的,好吧,我們使用GDB調試驗證一下:

 

 從調試的信息也是驗證了上面的結果.

 

另外一個(gè)問(wèn)題,優(yōu)先級有沒(méi)有范圍的? 

其實(shí)剛開(kāi)始我寫(xiě)的程序中的優(yōu)先級是1,我們將上面的程序改一下,然后編譯看一下會(huì )有什么樣的結果:

 

 

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

 

關(guān)于__attribute__的用法,可以有另外一種寫(xiě)法,先聲明函數,然后再定義.

 

 glibc多采用第一種寫(xiě)法.

 

關(guān)于linux內核中的"__attribute__ ((packed))"

引用:
__attrubte__ ((packed)) 的作用就是告訴編譯器取消結構在編譯過(guò)程中的優(yōu)化對齊,按照實(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)); /*  當用到typedef時(shí),要特別注意__attribute__ ((packed))放置的位置,相當于:
  *  typedef struct str_stuct str;
  *  而struct str_struct 就是上面的那個(gè)結構。
  */
typedef struct {
        __u8    a;
        __u8    b;
        __u8    c;
        __u16   d;
} __attribute__ ((packed)) str; /* 在下面這個(gè)typedef結構中,__attribute__ ((packed))放在結構名str_temp之后,其作用是被忽略的,注意與結構str的區別。*/
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;
}
編譯運行:
引用:
[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)和類(lèi)型屬性(Type Attribute)。 __attribute__書(shū)寫(xiě)特征是:__attribute__前后都有兩個(gè)下劃線(xiàn),并且后面會(huì )緊跟一對括弧,括弧里面是相應的__attribute__參數。 __attribute__語(yǔ)法格式為: __attribute__ ((attribute-list)) 其位置約束:放于聲明的尾部“;”之前。 函數屬性(Function Attribute):函數屬性可以幫助開(kāi)發(fā)者把一些特性添加到函數聲明中,從而可以使編譯器在錯誤檢查方面的功能更強大。__attribute__機制也很容易同非GNU應用程序做到兼容之功效。 GNU CC需要使用 –Wall編譯器來(lái)?yè)艋钤摴δ?,這是控制警告信息的一個(gè)很好的方式。 packed屬性:使用該屬性可以使得變量或者結構體成員使用最小的對齊方式,即對變量是一字節對齊,對域(field)是位對齊。

 

網(wǎng)絡(luò )通信通常分為基于數據結構的和基于流的。HTTP協(xié)議就是后者的一個(gè)例子。
    有時(shí)為了提高程序的處理速度和數據處理的方便,會(huì )使用基于數據結構的通信(不需要對流進(jìn)行解析)。但是,當需要在多平臺間進(jìn)行通信時(shí),基于數據結構的通信,往往要十分注意以下幾個(gè)方面:
[1] 字節序
[2] 變量長(cháng)度
[3] 內存對齊
     在常見(jiàn)的系統架構中(Linux X86,Windows),非單字節長(cháng)度的變量類(lèi)型,都是低字節在前,而在某些特定系統中,如Soalris  Sparc平臺,高字節在前。如果在發(fā)送數據前不進(jìn)行處理,那么由Linux X86發(fā)向Soalris  Sparc平臺的數據值,勢必會(huì )有極大的偏差,進(jìn)而程序運行過(guò)程中無(wú)法出現預計的正常結果,更嚴重時(shí),會(huì )導致段錯誤。
     對于此種情況,我們往往使用同一的字節序。在系統中,有ntohXXX(),  htonXXX()等函數,負責將數據在網(wǎng)絡(luò )字節序和本地字節序之間轉換。雖然每種系統的本地字節序不同,但是對于所有系統來(lái)說(shuō),網(wǎng)絡(luò )字節序是固定的  -----高字節在前。所以,可以以網(wǎng)絡(luò )字節序為通信的標準,發(fā)送前,數據都轉換為網(wǎng)絡(luò )字節序。
    轉換的過(guò)程,也建議使用ntohXXX(), htonXXX()等標準函數,這樣代碼可以輕松地在各平臺間進(jìn)行移植(像通信這種很少依賴(lài)系統API的代碼,做成通用版本是不錯的選擇)。

      變量的長(cháng)度,在不同的系統之間會(huì )有差別,如同是Linux2.6.18的平臺,在64位系統中,指針的長(cháng)度為8個(gè)字節,而在32位系統中,指針又是4個(gè)字   節的長(cháng)度---此處只是舉個(gè)例子,很少有人會(huì )將指針作為數據發(fā)送出去。下面是我整理的在64位Linux系統和32位Linux系統中,幾種常見(jiàn)C語(yǔ)言變  量的長(cháng)度:
                short    int    long    long long    ptr    time_t
32位           2         4       4             8               4        4
64位           2         4       8             8               8        8
    在定義通信用的結構體時(shí),應該考慮使用定常的數據類(lèi)型,如uint32_t,4字節的固定長(cháng)度,并且這屬于標準C庫(C99),在各系統中都可使用。

      內存對齊的問(wèn)題,也與系統是64位還是32位有關(guān)。如果你手頭有32位和64位系統,不妨寫(xiě)個(gè)簡(jiǎn)單的程序測試一下,你就會(huì )看到同一個(gè)結構體,即便使用了定   常的數據類(lèi)型,在不同系統中的大小是不同的。對齊往往是以4字節或8字節為準的,只要你寫(xiě)的測試程序,變量所占空間沒(méi)有對齊到4或8的倍數即可,舉個(gè)簡(jiǎn)單  的測試用的結構體的例子吧:
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
};
    在每個(gè)系統上看下這個(gè)結構體的長(cháng)度吧。
    內存對齊,往往是由編譯器來(lái)做的,如果你使用的是gcc,可以在定義變量時(shí),添加__attribute__,來(lái)決定是否使用內存對齊,或是內存對齊到幾個(gè)字節,以上面的結構體為例:
 1)到4字節,同樣可指定對齊到8字節。
struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((aligned(4))); 

2)不對齊,結構體的長(cháng)度,就是各個(gè)變量長(cháng)度的和
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.

Table of Contents
  1. __attribute__ format

  2. __attribute__ noreturn

  3. __attribute__ const

  4. Putting them together

  5. Compatibility with non-GNU compilers

  6. Other References

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

 

__ATTRIBUTE__ FORMAT

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:

  • __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.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.

__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 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!

__ATTRIBUTE__ CONST

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.

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, all programs 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 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 */ }

OTHER REFERENCES

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

http://www.unixwiz.net/techtips/gnu-c-attributes.html


*博客內容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀(guān)點(diǎn),如有侵權請聯(lián)系工作人員刪除。

DIY機械鍵盤(pán)相關(guān)社區:機械鍵盤(pán)DIY


電子鎮流器相關(guān)文章:電子鎮流器工作原理


電子鎮流器相關(guān)文章:





相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>