且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

ç多行宏:做/时(0)VS范围块

更新时间:2023-12-04 11:14:10

http://bytes.com/groups/c/219859-do-while-0-macro-substitutions

安德烈Tarasevich:

使用'做/而版本是使宏这将对整个构思
扩展成一个普通的语句,而不是成为一个复合语句。这是
为了使使用的函数式进行宏均匀的
在所有情况下使用的普通功能。

考虑以下code小品

 如果(小于条件>)
  富(一);
其他
  杆(一);

在这里'富'和'酒吧'是普通的功能。现在想象一下,你会
喜欢的上述性质的宏替换函数'富'

 如果(小于条件>)
  CALL_FUNCS(一);
其他
  杆(一);

现在,如果你的宏按照定义的第二种方法
(只是'{'和'}')在code将不再编译,因为真
由复合语句psented'如果',现在重新$ P $的分支。当你
把一个';'该复合语句后,你完成整个如果
声明中,从而成为孤儿的'其他'分支(因此编译错误)。

要解决此问题的方法之一是要记住不要把';'后
宏调用

 如果(小于条件>)
  CALL_FUNCS(一)
其他
  杆(一);

这将编译并达到预期效果,但这并不统一。该
更优雅的解决方案是确保宏观扩展到正规
声明中,不进一家化合物中的一个。实现的一个方法是定义
宏如下:

 的#define CALL_FUNCS(X)\\
做{\\
  func1的(X); \\
  FUNC2(X); \\
  FUNC3(X); \\
}而(0)

现在这个code

 如果(小于条件>)
  CALL_FUNCS(一);
其他
  杆(一);

将编译没有任何问题。

但是,请注意我的定义之间的微小但重要的区别
CALL_FUNCS ,并在邮件中的第一个版本。我没放
; },而(0)。把一个; 在该定义的结尾
马上会打败使用的整个点做/同时,使
宏观pretty多相当于复合语句版本。

我不知道为什么code您的作者在原始报价
消息把这个; 而(0)。在这种形式这两种变体
当量。背后使用做/而版本是不是整个想法
包括这最后的; 进入宏(我解释的原因
以上)。

Possible Duplicates:
What’s the use of do while(0) when we define a macro?
Why are there sometimes meaningless do/while and if/else statements in C/C++ macros?
do { … } while (0) what is it good for?

I've seen some multi-line C macros that are wrapped inside a do/while(0) loop like:

#define FOO \
  do { \
    do_stuff_here \
    do_more_stuff \
  } while (0)

What are the benefits (if any) of writing the code that way as opposed to using a basic block:

#define FOO \
  { \
    do_stuff_here \
    do_more_stuff \
  }

http://bytes.com/groups/c/219859-do-while-0-macro-substitutions

Andrey Tarasevich:

The whole idea of using 'do/while' version is to make a macro which will expand into a regular statement, not into a compound statement. This is done in order to make the use of function-style macros uniform with the use of ordinary functions in all contexts.

Consider the following code sketch

if (<condition>)
  foo(a);
else
  bar(a);

where 'foo' and 'bar' are ordinary functions. Now imagine that you'd like to replace function 'foo' with a macro of the above nature

if (<condition>)
  CALL_FUNCS(a);
else
  bar(a);

Now, if your macro is defined in accordance with the second approach (just '{' and '}') the code will no longer compile, because the 'true' branch of 'if' is now represented by a compound statement. And when you put a ';' after this compound statement, you finished the whole 'if' statement, thus orphaning the 'else' branch (hence the compilation error).

One way to correct this problem is to remember not to put ';' after macro "invocations"

if (<condition>)
  CALL_FUNCS(a)
else
  bar(a);

This will compile and work as expected, but this is not uniform. The more elegant solution is to make sure that macro expand into a regular statement, not into a compound one. One way to achieve that is to define the macro as follows

#define CALL_FUNCS(x) \
do { \
  func1(x); \
  func2(x); \
  func3(x); \
} while (0)

Now this code

if (<condition>)
  CALL_FUNCS(a);
else
  bar(a);

will compile without any problems.

However, note the small but important difference between my definition of CALL_FUNCS and the first version in your message. I didn't put a ; after } while (0). Putting a ; at the end of that definition would immediately defeat the entire point of using 'do/while' and make that macro pretty much equivalent to the compound-statement version.

I don't know why the author of the code you quoted in your original message put this ; after while (0). In this form both variants are equivalent. The whole idea behind using 'do/while' version is not to include this final ; into the macro (for the reasons that I explained above).