do while(0)在宏定義的妙用

    do{
        
        //do something

    ]while(0);

上面是一段使用 do while(0) 的代碼,顯然如上代碼只會執行一次,這樣使用顯然是毫無意義的的(當然莫種情況下還是有意義的,比如在裏面定義局部變量),所以在常規的代碼編寫中,我們並不會使用 do while(0) 這種結構。但是在Linux內核代碼中卻大量使用了do while(0) 這種結構:

圖1 內核代碼搜索while(0)結果截圖

那麼,通常在什麼時候使用呢,隨便點擊一個查看(其實其他都是同種類型):

圖2 內核源碼中do while(0)使用例子

細看,這居然是一個宏,(作爲小白,平時的宏都是一行的),其實像這樣複雜的宏,在內核源碼中非常常用,可以使代碼更加簡潔,也不會像函數那樣降低代碼運行速度。那麼爲什麼要使用 do while(0) 呢,我們使用一下例子分析:

例如我有這樣一個宏:

void fun1(){
	printf("fun1\n");
}
void fun2(){
	printf("fun2\n");
}

#define ifTrue	fun1(); fun2();        //複雜宏

那麼如果我有一下這樣的應用:

#define ifTrue	fun1(); fun2();

if(flag)            
   ifTrue;

預編譯展開宏之後:

#define ifTrue	fun1(); fun2();

if(flag)           
   fun1(); 
   fun2();

那麼就會出現一個問題,無論flag是什麼值 fun2() 都會被執行。程序邏輯就會錯誤。

所以有同學就說了,加個大括號不就行了嗎?就像這樣:

#define ifTrue	{fun1(); fun2();}        //複雜宏

那麼,程序預編譯展開宏之後將是這樣:

#define ifTrue	{fun1(); fun2();}

if(flag)           
   {fun1(); fun2();};
   

後面將多出一個分號(單獨的分號代表空語句),對於現在9102的編譯器當然沒問題,但是對於舊編譯器可能就會出現警告甚至是錯誤。怎麼去將宏統一又能消化掉後面的分號呢,do while(0) 結構就很好的解決了上面的所有煩惱,do while() 設計的初心應該是循環控制結構,但是卻被挖掘出另一種用途,這就是程序設計之美!

 

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