做{…} while(0) – 有什么好处?

可能重复:
为什么在C / C ++macros中有没有意义的do / while和if / else语句?

我已经看了十多年了。 我一直在想什么是好的。 因为我主要在#defines中看到它,所以我认为它适合于内部作用域variables声明和使用中断(而不是gotos)。

对其他东西有好处吗? 你用它吗?

它是C语言中唯一可以用来定义多语句操作的结构,在后面加一个分号,然后在if语句中继续使用。 一个例子可能有助于:

 #define FOO(x) foo(x); bar(x) if (condition) FOO(x); else // syntax error here ...; 

即使使用大括号也无济于事:

 #define FOO(x) { foo(x); bar(x); } 

if语句中使用这个会要求你省略分号,这是违反直觉的:

 if (condition) FOO(x) else ... 

如果你这样定义FOO:

 #define FOO(x) do { foo(x); bar(x); } while (0) 

那么以下句法正确:

 if (condition) FOO(x); else .... 

这是一种简化错误检查并避免深层嵌套的方法。 例如:

 do { // do something if (error) { break; } // do something else if (error) { break; } // etc.. } while (0); 

它有助于将多个语句组合成一个单独的语句,这样一个类似function的macros实际上可以用作函数。 假设你有

 #define FOO(n) foo(n);bar(n) 

而你呢

 void foobar(int n){ if (n) FOO(n); } 

那么这扩大到

 void foobar(int n){ if (n) foo(n);bar(n); } 

注意第二个调用(bar(n))不再是if语句的一部分。

将两者封装在do {} while(0)中,并且还可以在if语句中使用macros。

有趣的是,注意do {} while(0)循环不适用于你的以下情况:

如果你想要一个类似函数的macros来返回一个值,那么你需要一个语句expression式 :({stmt; stmt;})而不是do {} while(0):

 #include <stdio.h> #define log_to_string1(str, fmt, arg...) \ do { \ sprintf(str, "%s: " fmt, "myprog", ##arg); \ } while (0) #define log_to_string2(str, fmt, arg...) \ ({ \ sprintf(str, "%s: " fmt, "myprog", ##arg); \ }) int main() { char buf[1000]; int n = 0; log_to_string1(buf, "%s\n", "No assignment, OK"); n += log_to_string1(buf + n, "%s\n", "NOT OK: gcc: error: expected expression before 'do'"); n += log_to_string2(buf + n, "%s\n", "This fixes it"); n += log_to_string2(buf + n, "%s\n", "Assignment worked!"); printf("%s", buf); return 0; } 

一般来说, do / while对于任何一种必须至less执行一次循环的循环结构都是有用的。 有可能通过一个直的或者甚至一个for循环来模拟这种循环,但是通常结果是不那么优雅。 我承认这种模式的具体应用是相当less见的,但它们确实存在。 想到的一个是基于菜单的控制台应用程序:

 do { char c = read_input(); process_input(c); } while (c != 'Q');