do...while(0)解析

爲什麼在內核中碰到很多  #define ...  do{...} while(0) ?

有以下幾點原因:

1、空語句在編譯的時候會出現警告,所以有必要用#define FOO do{ } while(0)

2、給定一個基本塊,可以在裏面定義局部變量

3、爲了能夠在條件語句中使用複雜的宏定義。例如下面這段代碼:

[cpp] view plain copy
  1. #define FOO(x) \  
  2.         printf("arg is %s\n", x); \  
  3.         do_something_useful(x);  
如果這樣用:

[cpp] view plain copy
  1. if (blah == 2)  
  2.     F00(blah);  
宏展開之後爲

[cpp] view plain copy
  1. if (blah == 2)  
  2.         printf("arg is %s\n", blah);  
  3.         do_something_useful(blah);;  

這樣,if條件之後包含了printf()語句,而do_something_useful()調用不能按照預期那樣工作。而是用do {...} while(0)定義後,就會展開成以下語句:

[cpp] view plain copy
  1. if (blah == 2)  
  2. do{  
  3.               printf("arg is %s\n", blah);  
  4.               do_something_useful(blah);  
  5.   
  6. }while(0);  
這是我們所期望的。

如果你希望定義一個包含多行語句和一些局部變量的時候. 一般的定義方式只能這樣:

[cpp] view plain copy
  1. #define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }  
然而在某些情況下,這樣並不能正常工作. 下面是包含兩個分支的if語句:
[cpp] view plain copy
  1. if (x > y)  
  2.  exch(x,y);          // Branch 1  
  3. else  
  4.  do_something();     // Branch 2  
但這樣卻只能展開成單分支的if語句,如下:

[cpp] view plain copy
  1. if (x > y) {                // 單分支if  
  2.  int tmp;  
  3.  tmp = x;  
  4.  x = y;  
  5.  y = tmp;  
  6. }  
  7. ;                           // 空語句  
  8.  else                        // 錯誤!!! "parse error before else"  
  9.  do_something();  
問題是由於在語句塊後直接加入分號(;)引起的. 解決辦法是將語句塊放入 do 和 while (0)中間.這樣就得到了一條單語句, 而不是被編譯器判斷爲語句塊.現在的if語句如下:
[cpp] view plain copy
  1. if (x > y)  
  2.   do {  
  3.   int tmp;  
  4.   tmp = x;  
  5.   x = y;  
  6.   y = tmp;  
  7.   } while(0);  
  8.    else  
  9.   do_something();  
假設有這樣一個宏定義  
[cpp] view plain copy
  1. #define  macro(condition)  if(condition)  dosomething();    
現在在程序中這樣使用這個宏:  
[cpp] view plain copy
  1. if(temp)    
  2.      macro(i);    
  3. else    
  4.      doanotherthing();    

一切看起來很正常,但是仔細想想。這個宏會展開成:  
[cpp] view plain copy
  1. if(temp)    
  2.      if(condition)  dosomething();    
  3. else      
  4.      doanotherthing();    

這時的else不是與第一個if語句匹配,而是錯誤的與第二個if語句進行了匹配,編譯通過了,但是運行的結果一定是錯誤的。  

爲了避免這個錯誤,我們使用do{….}while(0)  把它包裹起來,成爲一個獨立的語法單元,從而不會與上下文發生混淆。同時因爲絕大多數的編譯器都能夠識別do{…}while(0)這種無用的循環並進行優化,所以使用這種方法也不會導致程序的性能降低。  
發佈了51 篇原創文章 · 獲贊 17 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章