C多行宏问题:为什么不在多行宏定义中使用if(1){…}而不是do {…} while(0)
我想调用循环中的多行宏来打破/继续它。
如果我在多行宏定义中使用“do {…} while(0)”,则break / continue仅对“do {…} while(0)”有效,而不是调用此宏的循环。 所以我考虑在多宏定义中使用“if(1){…}”。
#define EXIT_CIRCULATION() \ if(1){ \ break; \ } void func(){ while(1){ ... EXIT_CIRCULATION(); ... } }
但我怀疑在宏定义中使用“if(1){…}”是一种好方法,因为我在互联网上找不到任何例子。
谢谢!
如果你编码像
if (somecondition) EXIT_CIRCULATION(); else break;
然后你的宏的扩展将不会像你直觉期望的那样表现。 else
将适用于你的if (1)
并且永远不会发生。
这个技巧背后的整个想法是找到一种方法来创建一个多行(即复合)语句,该语句也包含一个终止;
作为其组成部分。 这将给你机会使用;
在宏调用之后,不会无意中引入空语句。
{ ... }
中的普通复合语句不起作用,因为它没有结束;
。 C / C ++中唯一以…结尾的多行语句;
是do/while
。 C / C ++语法中没有其他语句可以满足此要求。 (这是一个不准确的声明,请参阅下面的“PS”)
在所有其他情况下(包括你的if (1) {...}
) ;
宏调用之后将被视为另一个独立的独立空语句。 这样就不可能写出一个;
在宏调用之后,当它在需要完全一个语句的上下文中使用时(如if-else
真分支或do/while
循环的主体)。
例如,如果您定义
#define A() if (1) {}
那么这段代码将无法编译
do A(); while (1);
因为它将被取代
do if (1) {}; /* <- two statements, not one */ while (1);
这实际上是do
和while
之间的两个陈述。 在do
和while
之间指定两个语句而不将它们包装到{}
是语法错误。
PS更正:我上面提到的有关do/while
唯一可行变体的声明是不正确的。 在@Michael Burr的回答中,你可以看到另一个合适的变体,它使用else ((void) 0)
技巧用于相同的目的。 但是,主要原则仍然是相同的。
这是一个我认为可以安全地做你想要的宏:
#define EXIT_CIRCULATION() \ if (1) { \ /* some statements */ \ break; \ } \ else \ do {} while (0)
if
这里与else
匹配的事实意味着宏可以安全地在另一个中使用if
,并且因为else
子句是do-nothing do
/ while
语句,它提供类似的属性来包装多行宏do
/ do
。 例如,宏需要用分号终止,就像它是正常的声明一样; 忘记分号将导致语法错误。 它在另一个if
或else
子句中扮演的很好。
最重要的是对你(我认为), break
语句不会被宏吞没 – 它会打破宏所用的循环。
这是否是一个好主意完全是另一回事。 许多程序员不喜欢将流控制语句隐藏在宏中(除非控制流完全在宏单元内)。
这是在行动:
#include #include #define EXIT_CIRCULATION() \ if (1) { \ puts("done."); \ break; \ } \ else \ do {} while (0) int main() { int i = 0; for (i = 0; i < 10; ++i) { if (i > 4) EXIT_CIRCULATION(); else puts("working..."); } printf("i == %d\n", i); return 0; }
输出:
working... working... working... working... working... done. i == 5