在開源軟件里面經常可以看到這樣的寫法。
#define X(a) do { f1(a); f2(a); } while(0)
1. 主要作用是放在宏定義里面,避免宏帶來的語法問題。
比如
#define DOSOMETHING()\ cmd1;\ cmd2;
而調用的時候
if(a>0) DOSOMETHING(); 會有問題,需要用到上面提到的
而這時候,為什么不用 if (1) { ... } 呢?
有兩方面原因:
首先,會多出不必要的分號,比如:
if (1) my_code;
另外更重要的是,有if-else的問題:
if (1) my_code; else { ... }
當然了,如果定義成
#define X(a) if(1) { f1(a); f2(a); } else{}
就和下面的 do...while(0)一樣安全了。但是上面的if-else寫法不需要寫分號;,有利有弊。
#define X(a) do { f1(a); f2(a); } while(0)
2. 還有一個重要原因是,可以用來取代goto跳轉。
比如下面帶goto的代碼:
int foo() { somestruct* ptr = malloc(...); dosomething...; if(error) { goto END; } dosomething...; if(error) { goto END; } dosomething...; END: free(ptr); return 0; }
可以利用do...while(0)和break的配合,寫成:
int foo() { somestruct* ptr = malloc(...); do{ dosomething...; if(error) { break; } dosomething...; if(error) { break; } dosomething...; }while(0); free(ptr); return 0; }
goto轉換為do...while+break,在程序結構上、編譯優化上,都有很多好處。我覺得。
3、避免空宏引起的warning
內核中由於不同架構的限制,很多時候會用到空宏,在編譯的時候,空宏會給出warning,為了避免這樣的warning,就可以使用do{}while(0)來定義空宏:
#define EMPTYMICRO do{}while(0)
我覺得,這個也可以用if-else來代替。
4、定義一個單獨的函數塊來實現復雜的操作,避免作用域或者命名空間沖突
當你的功能很復雜,變量很多你又不願意增加一個函數的時候,使用do{}while(0);,將你的代碼寫在里面,里面可以定義變量而不用考慮變量名會同函數之前或者之后的重復。
(完)