C多行宏问题:为什么不使用if(1){..}而不是do{..}while(0)在多行宏定义中

C multi-line macro issue: why not use if(1){...} instead of do{...}while(0) in multi-line macro definition

本文关键字:while 宏定义 do 问题 为什么不 if      更新时间:2023-10-16

我想调用循环中的多行宏来中断/继续它。

如果我使用"do"{...}while(0)"在多行宏定义中,中断/继续仅对"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++语法中没有其他语句可以满足这一要求。(这是一个不准确的说法,请参阅下面我的"P.S.")

在所有其他情况下(包括if (1) {...}),宏调用后的;将被视为额外的独立空语句。这将使您无法在宏调用后编写;,因为它用于需要恰好一个语句的上下文(如if-else的真实分支或do/while循环的主体)。

例如,如果定义

#define A() if (1) {}

则该代码不会编译

do
A();
while (1);

因为它将被取代

do
if (1) {}; /* <- two statements, not one */
while (1);

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

p.S.更正:我上面关于do/while唯一的可行变体的说法是不正确的。在@Michael Burr的回答中,你可以看到另一个合适的变体,即出于同样的目的使用else ((void) 0)技巧。然而,主要原则保持不变。

这里有一个宏,我相信它可以安全地执行您想要的操作:

#define EXIT_CIRCULATION()  
if (1) {        
/* some statements */   
break;                  
}                           
else                        
do {} while (0)

这里的ifelse匹配,这意味着该宏在另一个if中使用是安全的,并且由于else子句是一个无所事事的do/while语句,它提供了与在do/while中包装多行宏类似的属性。例如,宏将需要以分号结尾,就像它是一个正常的语句一样;忘记分号会导致语法错误。它在另一个ifelse子句中起到了很好的作用。

对你来说(我认为)最重要的是,break语句不会被宏吞噬——它会打破宏使用的循环。

这是不是一个好主意完全是另一回事。许多程序员不喜欢流控制语句隐藏在宏中(除非控制流完全在宏单元中)。

它在这里发挥作用:

#include<stdio.h>
#include<stdlib.h>
#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 == %dn", i);
return 0;
}

输出:

working...
working...
working...
working...
working...
done.
i == 5