爲什麼在內核中碰到很多 #define ... do{...} while(0) ?
有以下幾點原因:
1、空語句在編譯的時候會出現警告,所以有必要用#define FOO do{ } while(0)
2、給定一個基本塊,可以在裏面定義局部變量
3、爲了能夠在條件語句中使用複雜的宏定義。例如下面這段代碼:
- #define FOO(x) \
- printf("arg is %s\n", x); \
- do_something_useful(x);
- if (blah == 2)
- F00(blah);
- if (blah == 2)
- printf("arg is %s\n", blah);
- do_something_useful(blah);;
這樣,if條件之後包含了printf()語句,而do_something_useful()調用不能按照預期那樣工作。而是用do {...} while(0)定義後,就會展開成以下語句:
- if (blah == 2)
- do{
- printf("arg is %s\n", blah);
- do_something_useful(blah);
- }while(0);
如果你希望定義一個包含多行語句和一些局部變量的時候. 一般的定義方式只能這樣:
- #define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }
- if (x > y)
- exch(x,y); // Branch 1
- else
- do_something(); // Branch 2
- if (x > y) { // 單分支if
- int tmp;
- tmp = x;
- x = y;
- y = tmp;
- }
- ; // 空語句
- else // 錯誤!!! "parse error before else"
- do_something();
- if (x > y)
- do {
- int tmp;
- tmp = x;
- x = y;
- y = tmp;
- } while(0);
- else
- do_something();
- #define macro(condition) if(condition) dosomething();
- if(temp)
- macro(i);
- else
- doanotherthing();
一切看起來很正常,但是仔細想想。這個宏會展開成:
- if(temp)
- if(condition) dosomething();
- else
- doanotherthing();
這時的else不是與第一個if語句匹配,而是錯誤的與第二個if語句進行了匹配,編譯通過了,但是運行的結果一定是錯誤的。
爲了避免這個錯誤,我們使用do{….}while(0) 把它包裹起來,成爲一個獨立的語法單元,從而不會與上下文發生混淆。同時因爲絕大多數的編譯器都能夠識別do{…}while(0)這種無用的循環並進行優化,所以使用這種方法也不會導致程序的性能降低。