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); 

这实际上是dowhile之间的两个陈述。 在dowhile之间指定两个语句而不将它们包装到{}是语法错误。

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 。 例如,宏需要用分号终止,就像它是正常的声明一样; 忘记分号将导致语法错误。 它在另一个ifelse子句中扮演的很好。

最重要的是对你(我认为), 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