linux核心 使用的 gnu c 擴充套件

2021-06-08 16:31:33 字數 3274 閱讀 9119

gnu cc是乙個功能非常強大的跨平台c編譯器,它對c語言提供了很多擴充套件,這些擴充套件對優化、目標**布局、更安全的檢查等方面提供了很強的支援。本文把支援gnu擴充套件的c語言稱為gnu c。

linux核心**使用了大量的gnu c擴充套件,以至於能夠編譯linux核心的唯一編譯器是gnu cc,以前甚至出現過編譯 linux核心要使用特殊的gnu cc版本的情況。本文是對linux核心使用的gnu c擴充套件的乙個彙總,希望當你讀核心原始碼遇到不理解的語法和語義時,能從本文找到乙個初步的解答,更詳細的資訊可以檢視gcc.info。

語句表示式

------------------------------------------

gnu c把包含在括號中的復合語句看做是乙個表示式,稱為語句表示式,它可以出現在任何允許表示式的地方,你可以在語句表示式中使用迴圈、區域性變數等,原本只能在復合語句中使用。例如:

#define min_t(type, x, y) ()

復合語句的最後乙個語句應該是乙個表示式,它的值將成為這個語句表示式的值。這裡定義了乙個安全的求最小值的巨集,在標準c中,通常定義為:

#define min(x,y) ((x) < (y) ? (x) : (y))

這個定義計算x和y分別兩次(x和y中的小者被計算兩次),當引數有***時,將產生不正確的結果。使用語句表示式只計算引數一次,避免了可能的錯誤。語句表示式通常用於巨集定義。

typeof

------------------------------------------

使用前一節定義的巨集需要知道引數的型別,利用typeof可以定義更通用的巨集,不必事先知道引數的型別,例如:

141: #define min(x,y) ()

這裡typeof(x)表示x的值型別,第142行定義了乙個與x型別相同的區域性常量_x並初使化為x,注意第144行的作用是檢查引數x和y的型別是否 相同(如果x和y的型別不同編譯器將會發出warning,並不影響後面語句的執行)。typeof可以用在任何型別可以使用的地方,通常用於巨集定義。

零長度陣列

------------------------------------------

gnu c允許使用零長度陣列,在定義變長物件的頭結構時,這個特性非常有用。例如:

struct minix_dir_entry ;

結構的最後乙個元素定義為零長度陣列,它不佔結構的空間。在標準c中則需要定義陣列長度為1,分配時計算物件大小比較複雜。

可變引數巨集

------------------------------------------

在 gnu c中,巨集可以接受可變數目的引數,就象函式一樣,例如:

#define kern_debug "<7>"

#define pr_debug(fmt,arg...) printk(kern_debug fmt,##arg)

這裡arg表示其餘的引數,可以是零個或多個,這些引數以及引數之間的逗號構成arg的值,在巨集擴充套件時替換arg,例如:

pr_debug("%s:%d",filename,line)

擴充套件為printk("<7>" "%s:%d", filename, line)

使用##的原因是處理arg不匹配任何引數的情況。如果arg的值為空,gnu c預處理器在這種特殊情況下,丟棄##之前的逗號,這樣

pr_debug("success!\n")

擴充套件為printk("<7>" "success!\n")

注意最後沒有逗號。

標號元素

------------------------------------------

標準c要求陣列或結構變數的初使化值必須以固定的順序出現, 在gnu c中,通過指定索引或結構網域名稱,允許初始化值以任意順序出現。指定陣列索引的方法是在初始化值前寫 '[index] =',要指定乙個範圍使用 '[first ... last] =' 的形式,例如:

static unsigned long irq_affinity [nr_irqs] = ;

將陣列的所有元素初使化為 ~0ul,這可以看做是一種簡寫形式。

要指定結構元素,在元素值前寫 'fieldname:',例如:

struct file_operations ext2_file_operations = ;

將結構ext2_file_operations的元素llseek初始化為generic_file_llseek,元素read 初始化genenric_file_read,依次類推。我覺得這是gnu c 擴充套件中最好的特性之一,當結構的定義變化以至元素的偏移改變時,這種初始化方法仍然保證已知元素的正確性。對於未出現在初始化中的元素,其初值為 0。

case範圍

------------------------------------------

gnu c 允許在乙個 case 標號中指定乙個連續範圍的值,例如:

case '0' ... '9': c -= '0'; break;

case 'a' ... 'f': c -= 'a'-10; break;

case 'a' ... 'f': c -= 'a'-10; break;

case '0' ... '9':

相當於case '0': case '1': case '2': case '3': case '4':

case '5': case '6': case '7': case '8': case '9':

宣告的特殊屬性

------------------------------------------

gnu cc預定義了兩個標誌符儲存當前函式的名字,__function__儲存函式在原始碼中的名字;__pretty_function__儲存帶語言特色的名字。在c函式中,這兩個名字是相同的,在c++函式中,__pretty_function__包括函式返回型別等額外資訊,linux核心只使用了__function__。

void ext2_update_dynamic_rev(struct super_block *sb)

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

linux核心中GNU C和標準C的區別

gnuc 是標準c 的擴充套件 1.從安全的最值定義可以想到區別有3點 1.1 支援將大括號的復合語句當成乙個表示式,成為語句表示式 1.2 typeof 關鍵字 可以獲取乙個變數的型別 1.3 巨集定義 可以帶變引數 2.uboot啟動的時候會進行相關初始化,其實就是呼叫相關硬體的初始化函式,不過...

gnu c 長度為0的陣列的使用

長度為的陣列在標準c和c 中是不允許的,如果使用長度為的陣列,編譯時會產生錯誤,提示陣列長度不能為。但在gnuc中,這種用法卻是合法的。它的最典型的用法就是位於陣列中的最後一項。struct description struct description thisline struct descrip...

Linux核心驅動GPIO的使用

linux核心中gpio 是最簡單 最常用的資源 和 interrupt dma,timer一樣 驅動程式,應用程式都能夠通過相應的介面使用gpio,gpio使用0 max int之間的整數標識,不能使用負數,gpio與 硬體體系密切相關的 不過linux 有乙個框架 處理gpio 能夠使用統一的介...