__attribute__關鍵字


GCC使用__attribute__關鍵字來描述函數,變量和數據類型的屬性,用於編譯器對源代碼的優化。

GCC使用__attribute__關鍵字來描述函數,變量和數據類型的屬性,用於編譯器對源代碼的優化。

描述函數屬性的幾個重要的關鍵字:

void noreturnfun() __attribute__((noreturn));//函數不會返回。

void centon() __attribute__((alias("__centon")));//設置函數別名,函數是__cencon,別名是centon.

void main_enter() __attribute__((constructor));//main_enter函數在進入main函數前調用

void main_exit() __attribute__((destructor));//main_exit函數在main函數返回后調用

void fun() __attribute__ ((noinline));//fun函數不能作為inline函數優化

void fun() __attribute__ ((section("specials”)));//將函數放到specials段中,而不是通常的text段中

no_instrument_function、constructor和destructor關鍵字主要用於剖析(profiling)源代碼的。

在調某個用函數之前和退出某個函數之后調用這些剖析函數,配合addr2line工具可以統計程序的運行狀態。__cyg_profile_func_enter和__cyg_profile_func_exit是GCC指定的進入和返回調用的函數名。配合no_instrument_function關鍵字屬性可以使用它記錄剖析數據,在編譯這樣的代碼的時候,需要在gcc的命令行中加入-finstrument-functions選項,如果要使用addr2line工具分析源代碼,則還要加上-g的gcc命令行選項使得源代碼中的符號可以保留。這2個函數需要2個參數,void *func_address是將要調用的函數地址,void *call_site是調用該函數的地址。

void __cyg_profile_func_enter( void *func_address, void *call_site )
                                __attribute__ ((no_instrument_function));

void __cyg_profile_func_exit ( void *func_address, void *call_site )
                                __attribute__ ((no_instrument_function));

constructor和destructo是對main函數做上述剖析的關鍵字,不過這個函數的名稱就可以不特定了,而且這樣的函數沒有參數。如下:

void __main_enter(void) __attribute__ ((constructor));

void __main_exit(void) __attribute__ ((destructor));

描述變量屬性的幾個重要的關鍵字:

int alivalue __attribute__ ((aligned(32)));//變量所存放的內存地址32字節邊界對齊

struct zrecord {
char id;
int zar[32] __attribute__ ((packed));
};//緊湊安排數據結構中的成員元素。如果不使用packed屬性則將zar數組按最小的對齊方式在內存中安排空間,X86平台為4,這樣在id和zar之間將會有3個字節的空洞存在。而使用了packed屬性后,將不會存在這樣的空洞。這次屬性是依賴與硬件平台的。

struct domx __attribute__ ((section(“domx”))) = { 0 };
int trigger __attribute__ ((section(“MONLOG”))) = 0; //不將全局變量放在默認的data或bss段中。而指定特定的段中。

描述數據類型的幾個重要的關鍵字:

struct blockm{

      char j[3];

}__attribute__((aligned(32)));//此數據類型的變量的內存地址32字節邊界對齊

 

復合聲明返回值(Compound Statements Returning a Value):

在一對圓括號中的最后一個表達式所計算的值為返回值。如:

int rslt = ({

                    int a=5;

                    a+3;

             });//rslt所獲得的返回值為8

這個特性的通常用處可書的P87(文檔P112)參考。

 

函數參數構造(Function Argument Construction):

GCC內建了3個函數,用於對某一函數的參數構造,調用相關函數,獲得相關函數的返回值。

void *__builtin_apply_args(void);//構造調用此函數的父函數的參數,這些參數都是保存在函數棧(stack)中的。

void *__builtin_apply(void (*func)(), void *arguments, int size);//調用相關函數,第一參數是相關函數的執政,第二個參數是剛才構造參數的函數的返回的指針,第三個參數是建立一個新的棧(stack)而從舊棧中復制數據的尺寸。

__builtin_return(void *result);//獲得相關函數的返回。參數是剛才調用相關函數的函數的返回指針。

如:

#include <stdio.h>
int passthrough();
int average();

int main(int argc,char *argv[])
{
   int result;
   result = passthrough();
   printf(“result=%d\n”,result);
   return (0);
}
int passthourgh(int a,int b,int c)
{
void *record;
void *playback;
void (* fn)() = (void (*) ()) average;
record = __builtin_apply_args();
playback = __builtin_apply(fn,record,128);
   __builtin_return(playback);
}

int average(int a,int b,int c)
{
   Return ((a+b+c)/3;
}

內聯函數(Inline function):

內聯函數在某些情況下類似與宏(macro)。

在一定條件下編譯,內聯函數將直接將代碼內嵌到調用它的父函數中,編譯時指定-O選項才可能被內嵌。也可以指定內嵌函數一個屬性“always_inline”強制內嵌。

有幾種情況將不內嵌,而作為普通函數調用:

1、 不確定數量參數的函數

2、 調用alloca類庫函數的

3、 有可變尺寸數組聲明的。

4、 非本地goto的。

5、 嵌套調用的。

使用ISO C標准的時候,可以使用__inline__關鍵字代替inline關鍵字。

在glib的regex_internal.h文件中有這么幾行:
#ifdef __GNUC__
# define __attribute __attribute__
#else
# define __attribute
#endif

原來兩個是一會事

 

__attribute__((visibility("default")))

這個關鍵字與gcc編譯參數-fvisibility=hidden配合使用,如果使用了hidden參數,那么該.so庫所有符號只對內可見,對外不可見,即使鏈接了這個.so庫,還是不能調用其中的符合(函數等);

對於大型工程,為了避免同名符號沖突(默認情況下,先鏈接的.so庫符號會被可執行程序先鏈接,即如果有兩個fun函數,分別在a.so 和 b.so,先鏈接a,則使用a的fun函數),可以先使用-fvisibility=hidden將所有符號隱藏,然后在需要對外的符號前添加__attribute__((visibility("default")))屬性來保證符號對外可見。

當然也可以反過來,將-fvisibility設置為"default"或不設置這個屬性,默認所有符號都對外可見,然后在不對外可見的函數或變量前添加__attribute__((visibility("hidden")))來隱藏該符號

 

 

 
這句主要作用是提示編譯器,對這個函數的調用需要像printf一樣,用對應的format字符串來check可變參數的數據類型。

例如:
extern int my_printf (void *my_object, const char *my_format, ...)
__attribute__ ((format (printf, 2, 3)));

format (printf, 2, 3)告訴編譯器,my_format相當於printf的format,而可變參數是從my_printf的第3個參數開始。

這樣編譯器就會在編譯時用和printf一樣的check法則來確認可變參數是否正確了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM