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

时间:2012-11-26 06:33:40

标签: c++ c gcc

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

如果我在多行宏定义中使用“do {...} while(0)”,则break / continue仅对“do {...} while(0)”有效,而不是调用的循环这个宏。所以我考虑在多宏定义中使用“if(1){...}”。

#define EXIT_CIRCULATION() \
        if(1){ \
           break; \
        }

void func(){
    while(1){
       ...
       EXIT_CIRCULATION();
       ...
    }
}

但我怀疑在宏定义中使用“if(1){...}”是一种好方法,因为我在互联网上找不到任何例子。

谢谢!

3 个答案:

答案 0 :(得分:10)

如果您编写类似

的代码
 if (somecondition)
    EXIT_CIRCULATION();
 else
    break;

然后宏的扩展将不会像你直觉所期望的那样。 else适用于您的if (1),永远不会发生。

答案 1 :(得分:2)

这个技巧背后的整个想法是找到一种方法来创建一个多行(即复合)语句,该语句还包含一个终止;作为其组成部分。这将使您有机会在宏调用后使用;,而不会无意中引入空语句。

{ ... }中的普通复合语句不起作用,因为它不会以;结尾。 C / C ++中唯一以;结尾的多行语句是do/while。 C / C ++语法中没有其他语句可以满足此要求。 (这是一个不准确的声明,见下面的“P.S.”)

在所有其他情况下(包括您的if (1) {...}),宏调用后的;将被视为其他独立的独立空语句。这将使您在宏调用后编写;时无法在需要完全一个语句的上下文中使用它(如if-else的真分支或{{{{ 1}}循环)。

例如,如果您定义

do/while

然后此代码将无法编译

#define A() if (1) {}

因为它将替换为

do
  A();
while (1);

这实际上是do if (1) {}; /* <- two statements, not one */ while (1); do之间的两个语句。在whiledo之间指定两个语句而不将它们包装到while中是语法错误。

<强> P.S。更正:我上面提到的关于{}只是 可行变体的说法不正确。在@Michael Burr的回答中,您可以看到另一个合适的变体,它使用do/while技巧用于相同的目的。但是,主要原则保持不变。

答案 2 :(得分:2)

这是一个我认为可以安全地做你想要的宏:

#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 == %d\n", i);

    return 0;
}

输出:

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