欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
GNU C 擴展之__attribute__ 機制簡(jiǎn)介|GNU,C 擴展,__attribute__ 機制

GNU C 擴展之__attribute__ 機制簡(jiǎn)介

作者:聶飛      來(lái)源:     發(fā)表時(shí)間:2006-06-25    瀏覽次數:66488     字號:    

 

摘要:
   
在學(xué)習linux內核代碼及一些開(kāi)源軟件的源碼(如:DirectFB),經(jīng)??梢钥吹接嘘P(guān)__attribute__的相關(guān)使用。本文結合自己的學(xué)習經(jīng)歷,較為詳細的介紹了__attribute__相關(guān)語(yǔ)法及其使用。

----------------------------------------------------------------
聲明:
    此文為原創(chuàng ),歡迎轉載,轉載請保留如下信息
    作者:聶飛(afreez)  北京-中關(guān)村
    聯(lián)系方式:afreez@sina.com (歡迎與作者交流)
    初次發(fā)布時(shí)間:2006-06-17
    不經(jīng)本人同意,不得用語(yǔ)商業(yè)或贏(yíng)利性質(zhì)目的,否則,作者有權追究相關(guān)責任!
------------------------------------------------------------------------------------------------------

GNU C的一大特色(卻不被初學(xué)者所知)就是__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è)很好的方式。下面介紹幾個(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, strftimestrfmon的參數表格式規則對該函數的參數進(jìn)行檢查。archetype指定是哪種風(fēng)格;string-index指定傳入函數的第幾個(gè)參數是格式化字符串;first-to-check指定從函數的第幾個(gè)參數開(kāi)始按上述規則進(jìn)行檢查。

具體使用格式如下:

__attribute__((format(printf,m,n)))

__attribute__((format(scanf,m,n)))

其中參數mn的含義為:

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è)函數的成員函數,那么mn的值可有點(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

2extern void myprint(const char *format,...) __attribute__((format(printf,1,2)));

3

4void 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));
 

為了方便理解,大家可以參考如下的例子:

 

//name: noreturn.c  ;測試__attribute__((noreturn))

extern void myexit();

 

int test(int n)

{

        if ( n > 0 )

       {

                myexit();

              /* 程序不可能到達這里*/

       }

        else

                return 0;

}

 

編譯顯示的輸出信息為:

 

$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, ...)
{
               /* 函數定義 */
}
 
更多的屬性含義參考:
http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html
 

變量屬性(Variable Attributes

關(guān)鍵字__attribute__也可以對變量(variable)或結構體成員(structure field)進(jìn)行屬性設置。這里給出幾個(gè)常用的參數的解釋?zhuān)嗟膮悼蓞⒖急疚慕o出的連接。

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

aligned (alignment)

該屬性規定變量或結構體成員的最小的對齊格式,以字節為單位。例如:

 

int x __attribute__ ((aligned (16))) = 0;
 

編譯器將以16字節(注意是字節byte不是位bit)對齊的方式分配一個(gè)變量。也可以對結構體成員變量設置該屬性,例如,創(chuàng )建一個(gè)雙字對齊的int對,可以這么寫(xiě):

 

struct foo { int x[2] __attribute__ ((aligned (8))); };
 

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

 

short array[3] __attribute__ ((aligned));
 

選擇針對目標機器最大的對齊方式,可以提高拷貝操作的效率。

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

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

packed

使用該屬性可以使得變量或者結構體成員使用最小的對齊方式,即對變量是一字節對齊,對域(field)是位對齊。

下面的例子中,x成員變量使用了該屬性,則其值將緊放置在a的后面:

 

               struct test
          {
            char a;
            int x[2] __attribute__ ((packed));
          };
 

其它可選的屬性值還可以是:cleanup,common,nocommon,deprecated,mode,section,shared,tls_model,transparent_union,unused,vector_size,weak,dllimport,dlexport等,

詳細信息可參考:

http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html#Variable-Attributes

類(lèi)型屬性(Type Attribute

關(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 f[3]; } __attribute__ ((aligned (8)));

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

 

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

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

 

struct S { short f[3]; } __attribute__ ((aligned));

 

這里,如果sizeofshort)的大小為2byte),那么,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)。

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

 

struct my_unpacked_struct

{

      char c;

      int i;

};

         

struct my_packed_struct

{

     char c;

     int  i;

     struct my_unpacked_struct s;

}__attribute__ ((__packed__));

 

其它屬性的含義見(jiàn):

http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Type-Attributes.html#Type-Attributes

變量屬性與類(lèi)型屬性舉例

下面的例子中使用__attribute__屬性定義了一些結構體及其變量,并給出了輸出結果和對結果的分析。

程序代碼為:

 

struct p

{

int a;

char b;

char c;

}__attribute__((aligned(4))) pp;

 

struct q

{

int a;

char b;

struct n qn;

char c;

}__attribute__((aligned(8))) qq;

 

 

int main()

{

printf("sizeof(int)=%d,sizeof(short)=%d.sizeof(char)=%d\n",sizeof(int),sizeof(short),sizeof(char));

printf("pp=%d,qq=%d \n", sizeof(pp),sizeof(qq));

 

return 0;

}

 

輸出結果:

 

sizeof(int)=4,sizeof(short)=2.sizeof(char)=1

pp=8,qq=24

 

分析

 

sizeof(pp):

sizeof(a)+ sizeof(b)+ sizeof(c)=4+1+1=6<23=8= sizeof(pp)

sizeof(qq):

sizeof(a)+ sizeof(b)=4+1=5

sizeof(qn)=8;qn是采用8字節對齊的,所以要在a,b后面添3個(gè)空余字節,然后才能存儲qn,

4+1+3+8+1=17

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

17<24+8=24= sizeof(qq)

 

更詳細的介紹見(jiàn):http://gcc.gnu.org

下面是一些便捷的連接:GCC 4.0 Function Attributes;GCC 4.0 Variable Attributes ;GCC 4.0 Type Attributes ;GCC 3.2 Function Attributes ;GCC 3.2 Variable Attributes ;GCC 3.2 Type Attributes ;GCC 3.1 Function Attributes ;GCC 3.1 Variable Attributes

 

Reference

1.有關(guān)__attribute__的相對簡(jiǎn)單的介紹:http://www.unixwiz.net/techtips/gnu-c-attributes.html

2__attribute__詳細介紹:http://gcc.gnu.org

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
gcc 對齊問(wèn)題
C 中字節對齊雜談
零基礎入門(mén)之結構體字節對齊
GNU C 與 ANSI C_風(fēng)繼續吹
GNU C與ANSI C
#pragma pack(push) 和#pragma pack(pop) 以及#pragma pack()
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久