本系列文章主要寫我在閱讀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