在Linux內核中,經常會看到do{}while(0)這樣的語句,剛開始會疑惑,認為do{}while(0)毫無意義,因為它只會執行一次,加不加do{}while(0)效果是完全一樣的,其實do{}while(0)只要用於宏定義中。
這裡用以個簡單點的宏來演示:
#define SAFE_FREE(P) do{free(p); p = NULL;}while(0)
假設這裡去掉do{}while(0),即定義SAFE_FREE為:
#define SAFE_FREE(P) free(p); p = NULL;
那麼以下代碼:
if(NULL!=P)
SAFE_FREE(P)
else
...// do something
會被展開為:
if(NULL!=P)
free(p); p = NULL;
else
...// do something
展開的代碼中存在兩個問題:
(1)if分支後有兩個語句,導致else分支沒有對應的if,編譯失敗;
(2)假設沒有else分支,則SAFE_FREE中的第二個語句無論if條件是否為真都會被執行。
將SAFE_FREE的第定義加上{}就可以解決上述問題了,即:
#define SAFE_FREE(P) {free(p); p = NULL;}
這樣,代碼:
if(NULL!=P)
SAFE_FREE(P)
else
...// do something
會被展開為:
if(NULL!=P)
{free(p); p = NULL;}
else
...// do something
但是,在C語言中,每個語句後面加個分號是一種約定俗成的習慣,那麼,如下代碼:
if(NULL!=P)
SAFE_FREE(P);
else
...// do something
將被展開為:
if(NULL!=P)
{free(p); p = NULL;};
else
...// do something
這樣,else分支就又沒有對應的if了,編譯將無法通過。假設用了do{}while(0),情況就不一樣了,同樣的代碼就會被展開為:
if(NULL!=P)
{free(p); p = NULL;}
else
...// do something
不會在出現編譯問題。 do{}while(0)的使用完全是為了保證宏定義的使用者能無編譯錯誤的使用宏,它不對其使用者做任何假設。