GNU __attribute__分析

1 概述

__attribute__機制可以設置函數屬性(Function Attribute)、變量屬性(Variable Attribute)和類型屬性(Type Attribute)。

主要有用於改變所申明或定義的函數或數據的特性。

2 規範

語法格式爲:

__attribute__ ((attribute-list))

其位置約束爲:

放於聲明的尾部“;”之前。

attribute_適用於函數的聲明而不是函數的定義。當需要使用該屬性的函數時,必須在同一個文件裏進行聲明.示例如下:

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

void die(const char *format, ...)
{
/* 函數定義 */
}

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

3 函數屬性(Function Attribute)

函數屬性可以幫助開發者把一些特性添加到函數聲明中,從而可以使編譯器在錯誤檢查方面的功能更強大。
GNU CC需要使用 –Wall編譯器來激活該功能。

3.1 __attribute__ format

該屬性告訴編譯器,按照printf, scanf, strftime或strfmon的參數表格式規則對該函數的參數進行檢查。也即檢查函數聲明和函數實際調用參數之間的格式化字符串是否匹配。

format的語法格式爲:

format (archetype, string-index, first-to-check)

參數說明:

"archetype” 指定是哪種風格;
“string-index” 指定傳入函數的第幾個參數是格式化字符串
    這裏需要注意:成員函數第一個參數爲隱含參數this。
“first-to-check” 指定從函數的第幾個參數開始按上述規則進行檢查。

示例:

extern void myprint(int l,const char *format,...) __attribute__((format(printf,2,3)));

3.2 __attribute__ noreturn

屬性 noreturn 用於函數,該屬性告訴編譯器,此函數從不返回值。

示例:

extern void exit(int)   __attribute__((noreturn));
extern void abort(void) __attribute__((noreturn));

3.3 __attribute__ const

該屬性只能用於帶有數值類型參數的函數上。

當重複調用帶有數值參數的函數時,由於返回值是相同的,所以此時編譯器可以進行優化處理,除第一次需要運算外,其它只需要返回第一次的結果就可以了,進而可以提高效率。該屬性主要適用於沒有靜態狀態(static state)和副作用的一些函數,並且返回值僅僅依賴輸入的參數。

const參數不能用在帶有指針類型參數的函數中,因爲該屬性不但影響函數的參數值,同樣也影響到了參數指向的數據,它可能會對代碼本身產生嚴重甚至是不可恢復的嚴重後果。

該屬性的函數不能有任何副作用或者是靜態的狀態,所以,類似getchar()或time()的函數是不適合使用該屬性的。

3.4 -finstrument-functions

該參數可以使程序在編譯時,在函數的入口和出口處生成instrumentation調用。恰好在函數入口之後並恰好在函數出口之前,將使用當前函數的地址和調用地址來調用下面的 profiling 函數。

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

第一個參數this_fn是當前函數的起始地址,可在符號表中找到;第二個參數call_site是指調用處地址。
instrumentation 也可用於在其它函數中展開的內聯函數。

3.5 no_instrument_function

如果使用了-finstrument-functions ,將在絕大多數用戶編譯的函數的入口和出口點調用profiling函數。使用該屬性,將不進行instrument操作。

3.6 constructor/destructor

若函數被設定爲constructor屬性,則該函數會在main()函數執行之前被自動的執行。類似的,若函數被設定爲destructor屬性,則該函數會在main()函數執行之後或者exit()被調用後被自動的執行。擁有此類屬性的函數經常隱式的用在程序的初始化數據方面。

3.7 unused

屬性 unused 用於函數和變量,表示該函數或變量可能不使用,這個屬性可以避免
編譯器產生警告信息。

3.8 section ("section-name")

屬性 section 用於函數和變量,通常編譯器將函數放在 .text 節,變量放在
.data 或 .bss 節,使用 section 屬性,可以讓編譯器將函數或變量放在指定的
節中。

3.9 __builtin_return_address (LEVEL)

內建函數 __builtin_return_address 返回當前函數或其調用者的返回地址,參數
LEVEL 指定在棧上搜索框架的個數,0 表示當前函數的返回地址,1 表示當前函數
的調用者的返回地址,依此類推。

3.10 __builtin_constant_p(EXP)

內建函數 __builtin_constant_p 用於判斷一個值是否爲編譯時常數,如果參數
EXP 的值是常數,函數返回 1,否則返回 0

3.11 __builtin_expect(EXP, C)

內建函數 __builtin_expect 用於爲編譯器提供分支預測信息,其返回值是整數表
達式 EXP 的值,C 的值必須是編譯時常數

4 變量屬性(Variable Attributes)

關鍵字__attribute__也可以對變量(variable)或結構體成員(structure field)進行屬性設置。

4.1 aligned (alignment)

屬性 aligned 用於變量、結構或聯合類型,指定變量、結構域、結構或聯合的對齊量,以字節爲單位。aligned屬性使被設置的對象佔用更多的空間,該屬性規定變量或結構體成員的最小的對齊格式。例如:

//編譯器將以16字節(注意是字節byte不是位bit)對齊的方式分配一個變量
int x __attribute__ ((aligned (16))) = 0; 

//創建一個雙字對齊的int
struct foo { int x[2] __attribute__ ((aligned (8))); }; 

//如果aligned後面不緊跟一個指定的數字值,那麼編譯器將依據你的目標機器情況使用最大最有益的對齊方式
short array[3] __attribute__ ((aligned));

4.2 packed

屬性 packed 用於變量和類型,用於變量或結構域時表示使用最小可能的對齊,用於枚舉、結構或聯合類型時表示該類型使用最小的內存。packed可以減小對象佔用的空間.使用該屬性可以使得變量或者結構體成員使用最小的對齊方式,即對變量是一字節對齊,對域(field)是位對齊。

例如:

//域 address 將緊接着 size 分配。
//屬性 packed 的用途大多是定義硬件相關的結構,使元素之間沒有因對齊而造成的空洞。
struct Xgt_desc_struct {
    unsigned short size;
    unsigned long address __attribute__((packed));
};

4.3 其他

可選的屬性值還可以是:

cleanup,common,nocommon,deprecated,mode,section,shared,tls_model,
transparent_union,unused,vector_size,weak,dllimport,dlexport等,

5 類型屬性(Type Attribute)

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

其用法與4中用法類似,可以參考上面的內容。

6 同時使用多屬性

可以在同一個函數聲明裏使用多個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)));

7 非GNU處理

如果使用的是非GNU C, 那麼就忽略__attribute__,忽略方法如下:

#ifndef __GNUC__
# define __attribute__(x) /*NOTHING*/
#endif
發佈了46 篇原創文章 · 獲贊 66 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章