玩linux多多少少會看到一個用法 do xxx while(0)。從邏輯上來看,似乎沒什麼特別的,甚至會懷疑是否多此一舉 (while 0不就是直接跳出嗎?)。事實上,這是有一定用途的,主要是避免文法錯誤。在define macro時,只有一個語句,如#define foo(x) bar(x); 這樣多半不會有問題。但較複雜的macro搭配if else等flow control時,就會產生文法上的問題,看下例:

#define foo(x) bar(x); qoo(x);
int main(int argc, char* argv[])
{
        if(1)
                foo(1);
        else
                printf("in else\n");

}

latrell:~/temp/ctest$ gcc dowhile.c
dowhile.c: In function ‘main’:
dowhile.c:11: error: ‘else’ without a previous ‘if’

使用-E看preprocess的結果如下,多了一個分號,文法錯誤。

int main(int argc, char* argv[])
{
 if(1)
  bar(1); qoo(1);;
 else
  printf("in else\n");

}

用大括弧呢?#define {foo(x) bar(x); qoo(x);}

顯示一樣的compiler error,因為還是多了一個分號。

int main(int argc, char* argv[])
{
 if(1)
  {bar(1); qoo(1);};
 else
  printf("in else\n");

}

當然可以寫成

int main(int argc, char* argv[])
{
 if(1)
  foo(1)  //不加結束的分號 
 else
  printf("in else\n");

}

這樣的確可以避開compile error,不過這樣不符合一般寫法,也很不易讀。

正解為do while 0,如下:

#define foo(x) do {bar(x); qoo(x);} while (0)
展開如下:

int main(int argc, char* argv[])
{
 if(1)
  do {bar(1); qoo(1);} while (0);
 else
  printf("in else\n");

}

do while 0具有封閉的功能,使用macro可多加利用,避免一些莫名其妙的bug。

Note: 通常macro後是不加分號的,所以不會寫成#define foo(x) do {bar(x); qoo(x);} while (0);

kezeodsnx 發表在 痞客邦 PIXNET 留言(2) 人氣()


留言列表 (2)

發表留言
  • Ike
  • 最近剛好在看debug Macro,看完後恍然大悟,感謝你的解惑~
  • Roger
  • if use if-statement always use braces, then no need this do while(0) macro,
    I think this is side-effect of linux coding style, which emphasis
    "Do not unnecessarily use braces where a single statement will do"
    I think it is bad idea.