我已经看到这个表达超过10年了。我一直在想它有什么好处。由于我主要在#define中看到它,所以我认为它适用于内部作用域变量声明和使用break(而不是gotos)。
它还有其他用处吗?你用它吗?
这是一种简化错误检查和避免深度嵌套if的方法。例如:
do { // do something if (error) { break; } // do something else if (error) { break; } // etc.. } while (0);
一般来说,do/while适用于必须执行一次循环至少的任何类型的循环构造。可以通过直接的while或甚至for循环来模拟这种类型的循环,但通常结果不太优雅。我承认这种模式的特定应用程序相当少,但确实存在。首先想到的是一个基于菜单的控制台应用程序:
do
while
for
do { char c = read_input(); process_input(c); } while (c != 'Q');
它有助于将多个语句组合成一个语句,这样类似函数的宏就可以实际用作函数。假设你有:
#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语句的一部分。
bar(n)
if
将两者包装到do { } while(0)中,你也可以在if语句中使用宏。
do { } while(0)
它是C语言中唯一可以用于#define多语句操作的构造,在后面加分号,并且仍然在if语句中使用。举个例子可能会有所帮助:
#define
#define FOO(x) foo(x); bar(x) if (condition) FOO(x); else // syntax error here ...;
即使使用大括号也无济于事:
#define FOO(x) { foo(x); bar(x); }
在if语句中使用this将要求省略分号,这是违反直觉的:
if (condition) FOO(x) else ...
如果你这样定义FOO:
#define FOO(x) do { foo(x); bar(x); } while (0)
那么下面的句子在语法上是正确的:
if (condition) FOO(x); else ....
有趣的是注意到下面的情况,其中do {} while(0)循环不会为你工作:
如果你想要一个返回值的类函数宏,那么你需要语句表达:({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; }