爲什麼宏定義總是要使用do-while語句呢?

         在閱讀linux內核代碼的過程中,經常會發現宏定義中使用了do-while語句。有時候覺得這種do-while語句顯得有點多餘?幹嘛非得使用它把函數塊包裹起來?像下面的

#define MARCO_FUN1() do{\

                                               Function();

                                               }while(0)

 

幹嘛不直接#define MARCO_FUN1 Function();就ok了。

 

後來想到如果MARCO_FUN1除了要實現Function功能外,還要實現Function2。如果仍舊直接定義的話是很容易出錯的,像這種:

for(;;)MARCO_FUN1();

那麼for循環只會將function1包括進去了!

 

當然這個是比較容易想到的破綻之一,更多的解釋如下:

 

 

1,空的宏定義避免warning:

#definefoo() do{}while(0)

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

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

#definefoo(x) \

action1();\

action2();

在以下情況下:

if(NULL== pPointer)

   foo();

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

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

#defineswitch(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)這種無

用的循環並進行優化,所以使用這種方法也不會導致程序的性能降低。

也許你會說,我們代碼的習慣是在每個判斷後面加上{}, 就不會有這種問題了,也就不需要do...while了,如:

if(...)

{

}

else

{

}

誠然,這是一個好的,應該提倡的編程習慣,但一般這樣的宏都是作爲library的一部分出現的,而對於一個library的作者,他所要做的就是讓其庫具有通用性,強壯性,因此他不能有任何對庫的使用者的假設,如其編碼規範,技術水平等。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章