do {} while (0) 用法

#define MACRO_NAME(para) do{macro content}while(0)的格式,總結了以下幾個原因:


1,空的宏定義避免warning:

#define foo() do{}while(0)


2,存在一個獨立的block,可以用來進行變量定義,進行比較複雜的實現。


3,如果出現在判斷語句過後的宏,這樣可以保證作爲一個整體來是實現:

#define foo(x) /

action1(); /

action2();

在以下情況下:

if(NULL == pPointer)

    foo();

就會出現action1和action2不會同時被執行的情況,而這顯然不是程序設計的目的。


4,以上的第3種情況用單獨的{}也可以實現,但是爲什麼一定要一個do{}while(0)呢,看以下代碼:

#define switch(x,y) {int tmp; tmp=x;x=y;y=tmp;}

if(x>y)

switch(x,y);

else        //error, parse error before else

otheraction();


在把宏引入代碼中,會多出一個分號,從而會報錯。
//------------------------------------------------
使用do{….}while(0) 把它包裹起來,成爲一個獨立的語法單元,
從而不會與上下文發生混淆。同時因爲絕大多數的編譯器都能夠識別do{…}while(0)這種無
用的循環並進行優化,所以使用這種方法也不會導致程序的性能降低。

爲什麼很多linux內核中宏#defines用do { ... } while(0)?

有很多原因:

Dave Miller的說法):

             編譯器對於空語句會給出告警,這是爲什麼#define FOO do{ }while(0);


              給定一個基本塊(局部可視域),定義很多局部變量;

(Ben Collins的說法):

             在條件代碼中,允許定義複雜的宏。可以想像有很多行宏,如下代碼:

  • #define FOO(x) /
             printf("arg is %s/n", x); /
             do_something_useful(x);
    現在,想像下面的應用:
    if (blah == 2)
             FOO(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);
  • 這纔是所期望的結果。
  • (Per Persson的說法):
  • 像 Miller and Collins指出的那樣,需要一個塊語句包含多個代碼行和聲明局部變量。但是,本質如下面例子代碼:
  • #define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }
  • 上面代碼在有些時候卻不能有效工作,下面代碼是一個有兩個分支的if語句:
  • if (x > y)

             exch(x,y);           // Branch 1
    else  
             do_something();      // Branch 2
  • 展開後代碼如下:
  • if (x > y) {                 // Single-branch if-statement!!!
             int tmp;             // The one and only branch consists
             tmp = x;             // of the block.
             x = y;
             y = tmp;
    }
    ;                            // empty statement
    else                         // ERROR!!! "parse error before else"
             do_something();
  • 問題是分號(;)出現在塊後面。解決這個問題可以用do{}while(0):
  • if (x > y)
             do {
                     int tmp;
                     tmp = x;
                     x = y;
                     y = tmp;
             } while(0);
    else
             do_something();
  •  Bart Trojanowski的說法):
  • Gcc加入了語句解釋,它提供了一個替代do-while-0塊的方法。對於上面的解決方法如下,並且更加符合常理
  • #define FOO(arg) ({ /

                typeof(arg) lcl; /
                lcl = bar(arg);   /
                lcl;              /
         })
發佈了30 篇原創文章 · 獲贊 4 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章