0、引言
我們在嵌入式開發的程序中,經常可以碰到在一些宏定義或者是代碼段中使用了do {...} while(0)的陳述句,從語意上理解,do {...} while(0)內的邏輯就只執行一次,并沒有回圈執行,粗略看來,似憾訓蛇添足了,那么為什么還需要在只執行一次的邏輯外面加上一層do {...} while(0)陳述句呢?實際上,在這些邏輯中使用do {...} while(0)的作用遠大于美化你的代碼,下面就來看看實際的使用場景,
1、用于定義一個作用域,避免替換的時候出錯
我們都知道,在程式中如果一些常量引數或者代碼陳述句反復出現,就可以使用宏定義來替代,預處理階段,對程式中所有出現的“宏名”,前處理器都會用宏定義中的字串替代,這稱為“宏替換”或“宏展開”,
這樣做可提高程式的通用性和易讀性,減少不一致性,一個較好的宏名可以更好的讓讀者理解常量引數的含義;同時程式易于修改,我們僅需要改變一個宏定義,就可以改變整個程式中出現的所有該常量或者陳述句,
但是有時可能程式代碼段中,出現多條陳述句重復連續的使用,這樣我們就可以嘗試使用一個復雜的宏來替換,你有可能會這樣定義:
1 #define REPLACE_FUN() funA(); funB()
本意是在程式中當出現funA()和funB()多條陳述句連續使用時,使用REPLACE_FUN()來替換,
1 if(判斷條件) 2 REPLACE_FUN();
但是實際上在預處理的時候,宏展開替換后變成了:
1 if(判斷條件) 2 funA(); 3 funB(); //此處funB()一定會執行,造成邏輯錯誤
可以看出,funB()不會按照判斷條件才去執行,而是變成了一條獨立的陳述句,而如果在宏中使用括號:
1 #define REPLACE_FUN() {funA(); funB();}
我們一般的代碼習慣都會在陳述句的末尾加上分號,因此也會出錯:
1 if(判斷條件) 2 REPLACE_FUN(); 3 //宏展開后為: 4 if(判斷條件) 5 { 6 funA(); 7 funB(); 8 }; //此處替換后多一個分號;導致編譯報錯
因此,針對這種多條重復陳述句的連續使用,如果想用宏替換實作這個作用域的功能,就可以考慮使用do {...} while(0)陳述句:
1 define REPLACE_FUN() \ 2 do{ \ 3 funA();\ 4 funB();\ 5 }while(0)\ 6 //宏展開前為: 7 if(判斷條件) 8 REPLACE_FUN(); 9 //宏展開后為: 10 if(判斷條件) 11 do{ 12 funA(); 13 funB(); 14 }while(0); //根據判斷條件,正確執行了一次邏輯
![]()
2、避免goto陳述句的使用
goto陳述句也稱為無條件轉移陳述句,使用后可以從多重回圈或者多個判斷中直接跳出,對于如下例子:
1 void fun(int a) 2 { 3 if(1 == a) 4 { 5 ...//todo 6 goto exit; 7 } 8 if(2 == a) 9 { 10 ...//todo 11 goto exit; 12 } 13 exit: 14 ...//todo 15 printf("a is error"\n); 16 }
但是為了程式結構的清晰,還是要盡量限制goto陳述句的使用,我們可以使用do {...} while(0)結構配合break跳出單層的回圈的方法來替代這種goto的用法,
1 int fun(int a) 2 { 3 do{ 4 if(1 == a) 5 { 6 ...//todo 7 break; 8 } 9 if(2 == a) 10 { 11 ...//todo 12 break; 13 } 14 }while(0); 15 ...//todo 16 printf("a is error"\n); 17 }
3、定義一個單獨的函式塊來實作復雜的操作
當某個函式程式功能較為復雜,在該函式的代碼段中如果不再單獨定義一個函式實作部分邏輯,可以使用do {...} while(0)作為一個代碼塊,將想要實作的邏輯放在do {...} while(0)中,同時在該在do {...} while(0)代碼塊中定義的變數,可以不用考慮和函式之前或者之后的變數名重復沖突的問題,但是為了代碼的易讀性,還是盡量宣告不同的變數名,
1 int a; 2 char b; 3 int func() 4 { 5 int a = 3; 6 char b = 5; 7 do{ 8 int a; 9 char b; 10 ......//todo 11 }while(0); 12 }
4、避免空宏的警告
有的時候,程式為了不同的平臺移植或者不同架構的限制,很多時候會先定義空宏,后續再根據實際的需要看是否定義具體內容,但是在編譯的時候,這些空宏可能會給出warning,為了避免這樣的warning,我們可以使用do{...}while(0)來定義空宏,這種情況不太常見,因為有很多編譯器已經支持空宏,
1 //空宏 2 #define EMPTY_FUN 3 //增加do{...}while(0)來定義空宏 4 #define EMPTY_FUN do{}while(0) //避免了可能的編譯warning
更多技術內容和書籍資料獲取,入群技術交流敬請關注“明解嵌入式”
?
本文來自博客園,作者:Sharemaker,轉載請注明原文鏈接:https://www.cnblogs.com/Sharemaker/p/17142670.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/544583.html
標籤:其他
