歡迎您光臨本站 註冊首頁

gcc核心擴展

←手機掃碼閱讀     火星人 @ 2014-03-26 , reply:0

  GNU C 允許聲明函數、變數和類型的特殊屬性,以便手工的代碼優化和更仔細的代碼檢查。要指定一個聲明的屬性,在聲明后寫
__attribute__ (( ATTRIBUTE ))

  其中 ATTRIBUTE 是屬性說明,多個屬性以逗號分隔。GNU C 支持十幾個屬性,這裡介紹最常用的:

   * noreturn

  屬性 noreturn 用於函數,表示該函數從不返回。這可以讓編譯器生成稍微優化的代碼,最重要的是可以消除不必要的警告信息比如未初使化的變數。例如:

++++ include/linux/kernel.h
47: # define ATTRIB_NORET __attribute__((noreturn)) ....
61: asmlinkage NORET_TYPE void do_exit(long error_code)
ATTRIB_NORET;

  * format (ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK)

  屬性 format 用於函數,表示該函數使用 printf, scanf 或 strftime 風格的參數,使用這類函數最容易犯的錯誤是格式串與參數不匹配,指定 format 屬性可以讓編譯器根據格式串檢查參數類型。例如:

++++ include/linux/kernel.h?
89: asmlinkage int printk(const char * fmt, ...)
90: __attribute__ ((format (printf, 1, 2)));

  表示第一個參數是格式串,從第二個參數起根據格式串檢查參數。

  * unused

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

  * section ("section-name")

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

++++ include/linux/init.h
78: #define __init __attribute__ ((__section__ (".text.init")))
79: #define __exit __attribute__ ((unused, __section__(".text.exit")))
80: #define __initdata __attribute__ ((__section__ (".data.init")))
81: #define __exitdata __attribute__ ((unused, __section__ (".data.exit")))
82: #define __initsetup __attribute__ ((unused,__section__ (".setup.init")))
83: #define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
84: #define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit")))

  連接器可以把相同節的代碼或數據安排在一起,Linux 內核很喜歡使用這種技術,例如系統的初始化代碼被安排在單獨的一個節,在初始化結束后就可以釋放這部分內存。

  * aligned (ALIGNMENT)

  屬性 aligned 用於變數、結構或聯合類型,指定變數、結構域、結構或聯合的對齊量,以位元組為單位,例如:

++++ include/asm-i386/processor.h
294: struct i387_fxsave_struct {
295: unsigned short cwd;
296: unsigned short swd;
297: unsigned short twd;
298: unsigned short fop;
299: long fip;
300: long fcs;
301: long foo;
......
308: } __attribute__ ((aligned (16)));

  表示該結構類型的變數以 16 位元組對齊。通常編譯器會選擇合適的對齊量,顯示指定對齊通常是由於體系限制、優化等原因。

  * packed

  屬性 packed 用於變數和類型,用於變數或結構域時表示使用最小可能的對齊,用於枚舉、結構或聯合類型時表示該類型使用最小的內存。例如:

++++ include/asm-i386/desc.h
51: struct Xgt_desc_struct {
52: unsigned short size;
53: unsigned long address __attribute__((packed));
54: };

  域 address 將緊接著 size 分配。屬性 packed 的用途大多是定義硬體相關的結構,使元素之間沒有因對齊而造成的空洞。

  當前函數名

  GNU CC 預定義了兩個標誌符保存當前函數的名字,__FUNCTION__ 保存函數在源碼中的名字__PRETTY_FUNCTION__ 保存帶語言特色的名字。在 C 函數中,這兩個名字是相同的,在 C++ 函數中,__PRETTY_FUNCTION__ 包括函數返回類型等額外信息,Linux 內核只使用了 __FUNCTION__。

++++ fs/ext2/super.c
98: void ext2_update_dynamic_rev(struct super_block *sb)
99: {
100: struct ext2_super_block *es = EXT2_SB(sb)->s_es;
101:
102: if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)
103: return;
104:
105: ext2_warning(sb, __FUNCTION__,
106: "updating to rev %d because of new feature flag, "
107: "running e2fsck is recommended",
108: EXT2_DYNAMIC_REV);

  這裡 __FUNCTION__ 將被替換為字元串 "ext2_update_dynamic_rev"。雖然__FUNCTION__ 看起來類似於標準 C 中的 __FILE__,但實際上 __FUNCTION__是被編譯器替換的,不象 __FILE__ 被預處理器替換。

內建函數

  GNU C 提供了大量的內建函數,其中很多是標準 C 庫函數的內建版本,例如memcpy,它們與對應的 C 庫函數功能相同,本文不討論這類函數,其他內建函數的名字通常以 __builtin 開始。

  * __builtin_return_address (LEVEL)

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

++++ kernel/sched.c
437: printk(KERN_ERR "schedule_timeout: wrong timeout "
438: "value %lx from %p\n", timeout,
439: __builtin_return_address(0));

  * __builtin_constant_p(EXP)

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

++++ include/asm-i386/bitops.h
249: #define test_bit(nr,addr) \
250: (__builtin_constant_p(nr) ? \
251: constant_test_bit((nr),(addr)) : \
252: variable_test_bit((nr),(addr)))

  很多計算或操作在參數為常數時有更優化的實現,在 GNU C 中用上面的方法可以根據參數是否為常數,只編譯常數版本或非常數版本,這樣既不失通用性,又能在參數是常數時編譯出最優化的代碼。

  * __builtin_expect(EXP, C)

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

++++ include/linux/compiler.h
13: #define likely(x) __builtin_expect((x),1)
14: #define unlikely(x) __builtin_expect((x),0)
++++ kernel/sched.c
564: if (unlikely(in_interrupt())) {
565: printk("Scheduling in interrupt\n");
566: BUG();
567: }

  這個內建函數的語義是 EXP 的預期值是 C,編譯器可以根據這個信息適當地重排語句塊的順序,使程序在預期的情況下有更高的執行效率。上面的例子表示處於中斷上下文是很少發生的,第 565-566 行的目標碼可能會放在較遠的位置,以保證經常執行的目標碼更緊湊。

[火星人 ] gcc核心擴展已經有463次圍觀

http://coctec.com/docs/linux/show-post-188883.html