GNU計(jì)劃,又稱革奴計(jì)劃,是由Richard Stallman在1983年9月27日公開發(fā)起的。它的目標(biāo)是創(chuàng)建一套完全自由的操作系統(tǒng),它在編寫Linux的時(shí)候自己制作了一個(gè)標(biāo)準(zhǔn)成為GNU C標(biāo)準(zhǔn),但是作為GNU C一大特色的__attribute__機(jī)制卻為許多人所不知,現(xiàn)在讓我們一起走進(jìn)__attribute__的世界,來揭開它的神秘面紗。
對(duì)于GNU C的__attribute__機(jī)制,它有什么神奇的作用呢?你們是不是已經(jīng)迫不及待了,對(duì)于__attribute__它可以修飾變量屬性和函數(shù)屬性,它的語法格式為:“__attribute__((參數(shù)));”,下面我們慢慢道來。
當(dāng)我們初次學(xué)習(xí)一門語言的時(shí)候,都會(huì)寫一個(gè)很經(jīng)典的程序,沒錯(cuò)就是在屏幕上輸出Hello world,現(xiàn)在對(duì)我們來說寫一段hello world程序,都是順手捏來的事了,那么你看過這樣的Hello world嗎?
#include
#include
__attribute__((constructor())) void pre_proc_1(void)
{
printf("\nhello world\n");
}
__attribute__((destructor())) void end_proc_1(void)
{
printf("\nHello World\n",__LINE__);
}
int main(int args,char **argv)
{
return 0;
}
可以猜到程序輸出什么結(jié)果嗎?沒錯(cuò)也是輸出Hello world,直到為什么這樣嗎?細(xì)心的人肯定看到了在兩個(gè)子函數(shù)前面使用了__attribute__((constructor()))和__attribute__((destructor))來修飾子函數(shù),那么它們的作用是什么意思呢?被__attribute__((constructor()))修飾的函數(shù)在主函數(shù)前執(zhí)行,__attribute__((destructor()))修飾的函數(shù)在主函數(shù)后執(zhí)行,我們還可以在__attribute__((constructor(101)))在數(shù)字,括號(hào)中的數(shù)字代表函數(shù)的優(yōu)先級(jí),這樣我們就可以安排我們函數(shù)執(zhí)行的順序了,一般0-100為系統(tǒng)使用,我們可以使用100以后的數(shù)字,在VC下也有這個(gè)屬性但是不能添加數(shù)字作為優(yōu)先級(jí),但是我們可以安排我們函數(shù)的聲明順序來實(shí)現(xiàn)函數(shù)的執(zhí)行順序。
經(jīng)過一個(gè)簡(jiǎn)單有意思的程序,下面我們繼續(xù)來說__attribute__機(jī)制,在前面說道__attribute__可以修飾變量和函數(shù)屬性,下面總結(jié)了如何使用__attribute__來修飾變量和函數(shù),讓我們一起來感受它的神奇。
函數(shù)屬性(1)__attribute__((format(archtype,string-index,first-to-check)));
format屬性告訴表達(dá)式按照printf,scanf,strftime,strfmom參數(shù)表格式規(guī)則對(duì)該函數(shù)的參數(shù)進(jìn)行檢查。
例:
__attribute__((format(printf,m,n)));
__attribute__((format(scanf,m,n)));
m:第幾個(gè)參數(shù)為格式化字符
n;在參數(shù)集合中排在第幾
(2)__attribute__((noreturn));
該屬性通知編譯器從不返回值,當(dāng)遇到類似函數(shù)需要返回值卻不可能運(yùn)行到返回值就已經(jīng)退出的情況該屬性可以避免出現(xiàn)錯(cuò)誤信息,例如C語言中的abort()和exit()函數(shù)就使用到了該屬性。
(3)__attribute__((const));
該屬性只能用于帶有數(shù)值類型參數(shù)的函數(shù)上,當(dāng)反復(fù)調(diào)用帶有數(shù)值參數(shù)的函數(shù)時(shí),由于返回值是相同的,所以編譯器可以進(jìn)行優(yōu)化處理,除第一次需要運(yùn)算外,其他只需返回第一次運(yùn)行的結(jié)果,進(jìn)而再快了執(zhí)行效率。
(4)Noinline & always_line
Nolinline為不內(nèi)聯(lián),always_line為總是內(nèi)聯(lián),我們?cè)谑褂胕nline什么內(nèi)聯(lián)函數(shù)時(shí),函數(shù)能否成為內(nèi)聯(lián)函數(shù),還要看編譯器的具體操作,使用noinline和always_line可以告訴編譯器是否執(zhí)行內(nèi)聯(lián)。
(5)看了前面的常用屬性,你們可能會(huì)問到可以在同一個(gè)函數(shù)中使用多個(gè)參數(shù)嗎?回答是肯定,并且這在實(shí)際中也是非常有用的。
變量屬性(1)__attribute__((aligned(n)));
例:
int a __attribute__((aligned(16))) = 0;
變量a將以16位對(duì)齊,我們也可以不加數(shù)字,如__attribute__((aligned));這樣編譯器會(huì)根據(jù)目標(biāo)機(jī)器的情況實(shí)現(xiàn)對(duì)齊。它不僅可以修飾單個(gè)變量,也可以修飾符合變量如結(jié)構(gòu)體,聯(lián)合等,在實(shí)際中會(huì)用于修飾結(jié)構(gòu)體,是結(jié)構(gòu)體中的成員按一定的方式字節(jié)對(duì)齊。
(2)__attribute__((packed));
例:
int a[10] __attribute__((packed));
前面說了字節(jié)對(duì)齊屬性,有的編譯會(huì)默認(rèn)使用一種字節(jié)對(duì)齊方式,假如我們不想使用字節(jié)對(duì)齊該怎么做呢?該屬性就起到了這個(gè)作用,使用packed可以取消字節(jié)對(duì)齊方式。
(3)__attribute__((at(address));
例:
int a __attribute__((at(0x00));
在一些特殊的情況,我們需要將某個(gè)變量存放特定的位置時(shí),該屬性就起到了作用,該屬性的作用就是將變量a存儲(chǔ)到絕對(duì)地址為0x00的位置處。
(4)__attribute__((section(“section_name”)));
例如:
int a(void) __attribute__((seciton(abc));
說了前面的at屬性,現(xiàn)在我們來說seciton屬性,他和at有些相同,他的作用是將作用的函數(shù)或指定的數(shù)據(jù)放入指定名為Section_name的段中,一般在匯編文件中我們會(huì)使用到。
(5)__attribute__((cleanup(函數(shù)名)))
該屬性來修飾一個(gè)變量,當(dāng)變量的作用域結(jié)束時(shí),調(diào)用一個(gè)指定的函數(shù)。
例如:
void print()(printf(“\nend\n”);
void text()
{
Int a __attribute__((cleanup(print))) = 10;
}
看了這么多屬性的作用,大家是否感覺到了GNU編譯器的神奇呢?對(duì)于__attribute__關(guān)鍵字,大家是否有了更進(jìn)一步的認(rèn)識(shí)呢?
-
Linux
+關(guān)注
關(guān)注
87文章
11342瀏覽量
210305 -
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
6889瀏覽量
123702 -
編譯器
+關(guān)注
關(guān)注
1文章
1642瀏覽量
49266
原文標(biāo)題:__attribute__ 你不知道的秘密
文章出處:【微信號(hào):Zlgmcu7890,微信公眾號(hào):周立功單片機(jī)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論