简体   繁体   English

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

I want to invoke multi-line macro in circulation to break/continue it. 我想调用循环中的多行宏来打破/继续它。

If I use "do{...}while(0)" in multi-line macro definition, break/continue is only effect on "do {...}while(0)", not the circulation who invoke this macro. 如果我在多行宏定义中使用“do {...} while(0)”,则break / continue仅对“do {...} while(0)”有效,而不是调用此宏的循环。 So I consider using "if(1){...}" in multi-macro definition. 所以我考虑在多宏定义中使用“if(1){...}”。

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

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

But I doubt wheather it is a good way to use "if(1){...}" in macro definition, because I can not find any example in internet. 但我怀疑在宏定义中使用“if(1){...}”是一种好方法,因为我在互联网上找不到任何例子。

Thanks! 谢谢!

if you code something like 如果您编写类似的东西

 if (somecondition)
    EXIT_CIRCULATION();
 else
    break;

then the expansion of your macro won't behave as you intuitively expect. 那么你的宏的扩展将不会像你直觉所期望的那样。 The else would apply to your if (1) and will never happen. else将适用于你的if (1)并且永远不会发生。

The whole idea behind this trick is to find a way to create a multi-line (ie compound) statement that also incorporates a terminating ; 这个技巧背后的整个想法是找到一种方法来创建一个多行(即复合)语句,该语句也包含一个终止; as its integral part. 作为其组成部分。 That will give you the opportunity to use ; 这将给你机会使用; after your macro invocation without inadvertently introducing an empty statement. 在宏调用之后,不会无意中引入空语句。

The ordinary compound statement in { ... } doesn't work because it does not end in ; { ... }中的普通复合语句不起作用,因为它没有结束; . The only multi-line statement in C/C++ that ends in ; C / C ++中唯一以...结尾的多行语句; is do/while . do/while There's no other statements in C/C++ grammar that would satisfy this requirement. C / C ++语法中没有其他语句可以满足此要求。 (This is an inaccurate claim, see my "PS" below) (这是一个不准确的声明,请参阅下面的“PS”)

In all other cases (including your if (1) {...} ) the ; 在所有其他情况下(包括你的if (1) {...}; after the macro invocation will be seen as an additional independent standalone empty statement. 宏调用之后将被视为另一个独立的独立空语句。 This will make it impossible to write a ; 这样就不可能写出一个; after your macro invocation when it is used in contexts requiring exactly one statement (like true branch of if-else or the body of do/while cycle). 在宏调用之后,当它在需要完全一个语句的上下文中使用时(如if-else真分支或do/while循环的主体)。

For example, if you define 例如,如果您定义

#define A() if (1) {}

then this code will not compile 那么这段代码将无法编译

do
  A();
while (1);

because it will be replaced with 因为它将被取代

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

and that is actually two statements between do and while . 这实际上是dowhile之间的两个陈述。 Specifying two statements between do and while without wrapping them into {} is syntax error. dowhile之间指定两个语句而不将它们包装到{}是语法错误。

PS Correction: The claim I make above about do/while being the only viable variant is incorrect . PS更正:我上面提到的关于do/while 唯一可行的变体的说法是不正确的。 In @Michael Burr's answer you can see another suitable variant, which is using the else ((void) 0) trick for the same purpose. 在@Michael Burr的回答中,你可以看到另一个合适的变体,它使用else ((void) 0)技巧用于相同的目的。 However, the main principle remains the same. 但是,主要原则仍然是相同的。

Here's a macro that I believe will safely do what you want: 这是一个我认为可以安全地做你想要的宏:

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

The fact that the if here is matched with an else means that the macro is safe to use inside another if , and since the else clause is a do-nothing do / while statement that provides the similar properties to wrapping a multi-line macro in a do / while . if这里与else匹配的事实意味着宏可以安全地在另一个内部使用if ,并且因为else子句是do-nothing do / while语句,它提供了类似的属性来包装多行宏一个do / while Such as the macro will need to be terminated by a semicolon as if it were a normal statement; 例如,宏需要用分号终止,就像它是正常的声明一样; forgetting the semicolon will result in a syntax error. 忘记分号将导致语法错误。 And it plays nice inside another if or else clause. 它在另一个ifelse子句中扮演的很好。

And most importantly for you (I think), the break statement isn't swallowed by the macro - it will break out the loop the macro is used in. 最重要的是对你(我认为), break语句不会被宏吞没 - 它将打破宏所用的循环。

Whether that's a good idea or not is something else entirely. 这是否是一个好主意完全是另一回事。 Many programmers don't like flow-control statements to be hidden within a macro (unless the flow of control is entirely within the macro unit). 许多程序员不喜欢将流控制语句隐藏在宏中(除非控制流完全在宏单元内)。

Here it is in action: 这是在行动:

#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;
}

output: 输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM