當第一次遇到do{...}while(0),我是懵的,這是什麼操作,爲了好看嗎?後來發現Linux內核中隨處可見啊,大神們這樣的操作肯定是有道理的。查詢了一些資料,做一下總結。在今後C語言開發中,你也可以放心使用這一技巧。
1. 配合定義複雜的宏,避免宏在預處理展開時出錯
舉個例子,假設你定義了一個宏:
#define DOSOMETHING() fuc1(); fuc2();
當調用DOSOMETHING()的時候,你希望調用fuc1()和fuc2()來做一些事情。但是當在if語句中調用時,可能會這麼寫:
if(num > 0)
DOSOMETHING();
預處理展開宏,替換文本如下:
if(num > 0)
fuc1();
fuc2();
這樣就出現了問題,fuc2()就不受if語句的控制了,導致程序出錯。
可能你會說,宏定義建議把整個表達式用大括號括起來的:
#define DOSOMETHING() {fuc1(); fuc2();}
還是if語句來調用:
if(num > 0)
DOSOMETHING();
else
printf("num<0\r\n");
這樣程序編譯會報錯:
我們查看預處理文件,宏展開是這樣子的:
if語句被後面的分號提前結束,else無法與其匹配。而使用do{...}while(0)後就不會出錯了,Linux內核中的宏定義很多都是這麼用的:
2. 避免定義空的宏時引起warning
一些大型的C工程中,爲了兼容不同的架構,或者爲了移植方便,都會用到空的宏定義。在編譯的時候,編譯器會給出警告,爲了避免這些warning,我們可以使用do{...}while(0)來定義空的宏:
3. 避免goto語句
在一些函數中,我們可能需要在return語句之前做一些清理工作,很多人不提倡用goto語句。好吧,do{...}while(0)可以實現同樣的功能:
int foo()
{
somestruct *ptr = malloc(...);
do
{
dosomething...;
if(error)
break;
dosomething...;
if(error)
break;
dosomething...;
}
while(0);
free(ptr);
return 0;
}
代碼可讀性和可維護性要比goto語句好多了。
4. 定義單一的函數塊來完成複雜的操作
當你的功能複雜,變量很多又不願增加一個函數的時候,可以將你的代碼用do{...}while(0)包裹,在裏面可以定義變量而不用考慮變量名會同函數前後重複。當然,爲了後續維護方便,不建議這麼做。
5. 就是感覺美觀好看
對,就是覺得好看,不解釋: