Linux Kernel 代碼藝術——編譯時斷言


本系列文章主要寫我在閱讀Linux內核過程中,關注的比較難以理解但又設計巧妙的代碼片段(不關注OS的各個模塊的設計思想,此部分我准備寫在“深入理解Linux Kernel” 系列文章中),一來通過內核代碼復習一下C語言及匯編語言的語法,二來學習內核開發大牛們書寫代碼的風格及思路。

在內核文件 include/linux/bug.h中,有下面兩行的宏定義:

1
2
3
4
5
6
 
/* Force a compilation error if condition is true, but also produce a
   result (of value 0 and type size_t), so the expression can be used
   e.g. in a structure initializer (or where-ever else comma expressions
   aren't permitted). */

#define BUILD_BUG_ON_ZERO(e) ( sizeof ( struct { int :-!!(e); }))
#define BUILD_BUG_ON_NULL(e) (( void *) sizeof ( struct { int :-!!(e); }))

以第一個分析,它表示的是:檢查表達式e是否為0,為0編譯通過且返回0;如果不為0,則編譯不通過。

可能從這個宏的名字上看可能容易理解錯,或者改為“BUILD_BUG_OR_ZERO”更好,關於這個的討論有人也提交這個patch(http://lkml.indiana.edu/hypermail/linux/kernel/0703.1/1546.html),但未能被社區接受。我們且不管這個宏定義名字怎樣,來逐步分析一下這個宏是如何來實現的:

  sizeof(struct { int : –!!(e); } ))

1. (e): 表達式e的聲明

2. !!(e): 對e的結果進行兩次求非。即如果e開始是0的話,結果就是0;如果e不為0,則結果為1。

3. –!!(e): 再乘以-1。如果第2步結果為0,則仍為0;否則結果為-1。

4. struct { int : –!!(0); }  -->  struct { int : 0; } : 如果e的結果為0,則我們聲明一個結構體擁有一個int型的數據域,並且規定它所占的位的個數為0。這沒有任何問題,我們認為一切正常。

5. struct { int : –!!(1); }  -->  struct { int : –1; } : 如果e的結果非0,結構體的int型數據域的位域將變為一個負數,將位域聲明為負數這是一個語法的錯誤。

6. 現在要么結果為聲明了一個位域為0的結構體,要么出現位域為負數編譯出錯;如果能正確編譯,然后我們對該結構體進行sizeof操作,得到一個類型為size_t的結果,值為0。

再總結一下,BUILD_BUG_ON_ZERO(e) 表示的就是若表達式e結果為0,則編譯通過,該宏的值也為0;若表達式e的結果不為0,則編譯不通過。

這會讓人聯想到C語言中 assert 宏的用法:

  void assert(int expression);

如果參數expression 計算的結果為0,它先向stderr打印一條出錯信息,然后通過調用 abort 來終止程序運行;否則斷言成立,繼續執行。

我們討論的宏與assert本質區別在於,我們的宏在編譯時進行測試,而assert宏是在運行時測試。我們希望能盡早地捕獲到我們編譯時的錯誤,而不是推遲到運行時。我管這種宏用法叫做“編譯時斷言”,assert為“運行時斷言”。

理解了上面之后,再來看看第二個BUILD_BUG_ON_NULL(e)宏,與第一個類似,用來在編譯時斷言e是否為NULL,若是這個宏返回(void *)0 (即NULL,與第一個宏的區別);不為NULL時編譯出錯。

除了上面的兩個編譯時斷言之外,include/linux/bug.h文件中還有另幾個大家可以思考表示何意,如:

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))   

#define BUILD_BUG_ON_NOT_POWER_OF_2(n)            \ 
    BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))

 

含義可以參考文件中宏定義的注釋說明。

 

-------------------------------------完--------------------------------

 

參考資料:

http://blog.csdn.net/jiyucn/article/details/862085   C語言中關於結構體位域的詳細說明

http://blog.csdn.net/jiyucn/article/details/862062   C語言中sizeof相關問題

http://www.cplusplus.com/reference/cassert/assert/   assert用法說明

http://stackoverflow.com/questions/9229601/what-is-in-c-code   問題及解答均來源於Stackoverflow

 

 


免責聲明!

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



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