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