本系列文章主要寫我在閱讀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檔案中還有另幾個大家可以思考表示何意,如:
1 2 3 4 |
#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