巨集定義中的do while
阿新 • • 發佈:2019-01-27
無論是Linux核心還是其他著名的c、c++庫裡都能見到 do{} while (0)
這樣的寫法看似沒有意義,其實出自名家之手,是在巨集定義裡使用的
以前就瞭解到在程式裡使用巨集定義的函式後面的分號容易導致問題,今天算是深入認識了
先看一個簡單的巨集
#define SAFE_FREE(p) do {free(p);p=NULL;} while(0)
如果去掉了do... while(0)
即定義SAFE_FREE(p)為
#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
這樣就導致if後面有兩條語句,第二條語句總會執行,且else不再與原來的if匹配
所以一般聰明的人在定義巨集函式的時候會加上 {}
#define SAFE_FREE(p) { free(p);p=NULL;}
這樣貌似解決了問題,可是還是有隱患
因為很多人習慣在C程式碼最後都加 ;
沒有經驗的人往往會不管那個SAFE_FREE(p)全是大寫,直接在後面加上;
如
if(NULL!=p)
SAFE_FREE(p);
else
//do something
被展開為
if(NULL!=p)
{ free(p);p=NULL;};
else
//do something
這樣 仍然導致if和else的匹配被破壞的情況
如果使用名家的方法
#define SAFE_FREE(p) do {free(p);p=NULL;} while(0)
那麼
if(NULL!=p)
SAFE_FREE(p);
else
//do something
展開為
if(NULL!=p)
do
{ free(p);p=NULL;}
while(0);
else
//do something
好了 這樣就一切太平了
書上是這麼說,可是我認為雖然採用了
#define SAFE_FREE(p) do {free(p);p=NULL;} while(0) 這樣的定義
可是使用者要是突然意識到SAFE_FREE(p)是個巨集,然後自作聰明沒有在SAFE_FREE(p)後加;
如
if(NULL!=p)
SAFE_FREE(p)
else
//do something
這樣展開
if(NULL!=p)
do
{ free(p);p=NULL;};
while(0)
else
//do something
這樣while(0)後面沒有; 仍然報錯!
聰明反被聰明誤,只因為還不夠聰明。
解決問題最簡單的方法就是良好的程式設計習慣
一個沒有任何問題的if else結構就能解決所有的問題
if(NULL!=P)
{//do something }
else
{ //do something }
就是兩點,NULL!=P而不是p!=NULL ,還有就是齊全的{}匹配
說來容易,但是我們在網上甚至是名著裡仍然很難看到完美的寫法
不要偷懶,少打那麼幾個{},否則會付出更慘痛的代價