linux内核 extern,Linux内核之_attribute_
GCC 的一大特色就是__attribute__機制。
__attribute__可以設置函數(shù)屬性(Function Attribute)、變量屬性(Variable Attribute)和類型屬性(Type Attribute)。
attribute前后都有兩個下劃線,后面會緊跟一對原括弧,括弧里面是相應的__attribute__參數(shù)。
語法格式為:__attribute__ ((attribute-list))
其位置約束為:放于聲明尾部“;”之前。
函數(shù)屬性(Function Attribute)
函數(shù)屬性可以幫助開發(fā)者把一些特性添加到函數(shù)聲明中,從而可以使編譯器在錯誤檢查方面的功能更強大
__attribute__ format
該__attribute__屬性可以給被聲明的函數(shù)加上類似printf或者scanf的特征,它可以使編譯器檢查函數(shù)聲明和函數(shù)實際調用參數(shù)之間的格式化字符串是否匹配。該功能十分有用,尤其是處理一些很難發(fā)現(xiàn)的bug。
format的語法格式為:
format (archetype, string-index, first-to-check)
format屬性告訴編譯器,按照printf, scanf, strftime或strfmon的參數(shù)表格式規(guī)則對該函數(shù)的參數(shù)進行檢查。“archetype”指定是哪種風格;“string-index”指定傳入函數(shù)的第幾個參數(shù)是格式化字符串;“first-to-check”指定從函數(shù)的第幾個參數(shù)開始按上述規(guī)則進行檢查。
具體使用格式如下:
__attribute__((format(printf,m,n)))
__attribute__((format(scanf,m,n)))
其中參數(shù)m與n的含義為:
m:第幾個參數(shù)為格式化字符串(format string);
n:參數(shù)集合中的第一個,即參數(shù)“…”里的第一個參數(shù)在函數(shù)參數(shù)總數(shù)排在第幾,注意,有時函數(shù)參數(shù)里還有“隱身”的呢,后面會提到;
在使用上,__attribute__((format(printf,m,n)))是常用的,而另一種卻很少見到。下面舉例說明,其中myprint為自己定義的一個帶有可變參數(shù)的函數(shù),其功能類似于printf:
//m=1;n=2
extern void myprint(const char *format,...) __attribute__((format(printf,1,2)));
//m=2;n=3
extern void myprint(int l,const char *format,...) __attribute__((format(printf,2,3)));
需要特別注意的是,如果myprint是一個函數(shù)的成員函數(shù),那么m和n的值可有點“懸乎”了,例如:
//m=3;n=4
extern void myprint(int l,const char *format,...) __attribute__((format(printf,3,4)));
其原因是,類成員函數(shù)的第一個參數(shù)實際上一個“隱身”的“this”指針。(有點C++基礎的都知道點this指針,不知道你在這里還知道嗎?)
__attribute__ noreturn
該屬性通知編譯器函數(shù)從不返回值,當遇到類似函數(shù)需要返回值而卻不可能運行到返回值處就已經(jīng)退出來的情況,該屬性可以避免出現(xiàn)錯誤信息。C庫函數(shù)中的abort()和exit()的聲明格式就采用了這種格式,如下所示:
extern void exit(int) __attribute__((noreturn));
extern void abort(void) __attribute__((noreturn));
__attribute__ const
該屬性只能用于帶有數(shù)值類型參數(shù)的函數(shù)上。當重復調用帶有數(shù)值參數(shù)的函數(shù)時,由于返回值是相同的,所以此時編譯器可以進行優(yōu)化處理,除第一次需要運算外,其它只需要返回第一次的結果就可以了,進而可以提高效率。該屬性主要適用于沒有靜態(tài)狀態(tài)(static state)和副作用的一些函數(shù),并且返回值僅僅依賴輸入的參數(shù)。
為了說明問題,下面舉個非常“糟糕”的例子,該例子將重復調用一個帶有相同參數(shù)值的函數(shù),具體如下:
extern int square(int n) __attribute__((const));
for (i = 0; i < 100; i++ )
{
total += square(5) + i;
}
通過添加__attribute__((const))聲明,編譯器只調用了函數(shù)一次,以后只是直接得到了相同的一個返回值。
同時使用多個屬性
可以在同一個函數(shù)聲明里使用多個__attribute__,并且實際應用中這種情況是十分常見的。使用方式上,你可以選擇兩個單獨的__attribute__,或者把它們寫在一起,可以參考下面的例子:
extern void die(const char *format, ...)
__attribute__((noreturn))
__attribute__((format(printf, 1, 2)));
section ("section-name")
屬性 section 用于函數(shù)和變量,通常編譯器將函數(shù)放在 .text 節(jié),變量放在.data 或 .bss 節(jié),使用 section 屬性,可以讓編譯器將函數(shù)或變量放在指定的節(jié)中。
例如:
++++ 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")))
連接器可以把相同節(jié)的代碼或數(shù)據(jù)安排在一起,Linux 內核很喜歡使用這種技術,
例如系統(tǒng)的初始化代碼被安排在單獨的一個節(jié),在初始化結束后就可以釋放這部分內存。
* aligned (ALIGNMENT)
屬性 aligned 用于變量、結構或聯(lián)合類型,指定變量、結構域、結構或聯(lián)合的對齊量,以字節(jié)為單位,
例如:
++++ 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 字節(jié)對齊。通常編譯器會選擇合適的對齊量,顯示指
定對齊通常是由于體系限制、優(yōu)化等原因。
* packed
屬性 packed 用于變量和類型,用于變量或結構域時表示使用最小可能的對齊,用
于枚舉、結構或聯(lián)合類型時表示該類型使用最小的內存。例如:
++++ include/asm-i386/desc.h
51: struct Xgt_desc_struct {
52: unsigned short size;
53: unsigned long address __attribute__((packed));
54: };
域 address 將緊接著 size 分配。屬性 packed 的用途大多是定義硬件相關的結
構,使元素之間沒有因對齊而造成的空洞。
當前函數(shù)名
==========
GNU CC 預定義了兩個標志符保存當前函數(shù)的名字,__FUNCTION__ 保存函數(shù)在源碼
中的名字,__PRETTY_FUNCTION__ 保存帶語言特色的名字。在 C 函數(shù)中,這兩個
名字是相同的,在 C++ 函數(shù)中,__PRETTY_FUNCTION__ 包括函數(shù)返回類型等額外
信息,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__ 被預處理器替換。
內建函數(shù)
GNU C 提供了大量的內建函數(shù),其中很多是標準 C 庫函數(shù)的內建版本,例如
memcpy,它們與對應的 C 庫函數(shù)功能相同,本文不討論這類函數(shù),其他內建函數(shù)
的名字通常以 __builtin 開始。
* __builtin_return_address (LEVEL)
內建函數(shù) __builtin_return_address 返回當前函數(shù)或其調用者的返回地址,參數(shù)
LEVEL 指定在棧上搜索框架的個數(shù),0 表示當前函數(shù)的返回地址,1 表示當前函數(shù)
的調用者的返回地址,依此類推。例如:
++++ 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)
內建函數(shù) __builtin_constant_p 用于判斷一個值是否為編譯時常數(shù),如果參數(shù)
EXP 的值是常數(shù),函數(shù)返回 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)))
很多計算或操作在參數(shù)為常數(shù)時有更優(yōu)化的實現(xiàn),在 GNU C 中用上面的方法可以
根據(jù)參數(shù)是否為常數(shù),只編譯常數(shù)版本或非常數(shù)版本,這樣既不失通用性,又能在
參數(shù)是常數(shù)時編譯出最優(yōu)化的代碼。
* __builtin_expect(EXP, C)
內建函數(shù) __builtin_expect 用于為編譯器提供分支預測信息,其返回值是整數(shù)表
達式 EXP 的值,C 的值必須是編譯時常數(shù)。例如:
++++ 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: }
這個內建函數(shù)的語義是 EXP 的預期值是 C,編譯器可以根據(jù)這個信息適當?shù)刂嘏?/p>
語句塊的順序,使程序在預期的情況下有更高的執(zhí)行效率。上面的例子表示處于中
斷上下文是很少發(fā)生的,第 565-566 行的目標碼可能會放在較遠的位置,以保證
經(jīng)常執(zhí)行的目標碼更緊湊。
總結
以上是生活随笔為你收集整理的linux内核 extern,Linux内核之_attribute_的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软件测试工作常用linux命令,软件测试
- 下一篇: gitlab linux版本下载,Lin