空函数宏

Qix*_*Qix 35 c++ macros compilation function

如果我定义一个没有实际主体的函数宏,它是否像编译器的空字符串(即它在编译时不生成任何额外的指令)?

例:

#define SomeMacro(a)

SomeMacro("hello"); // This line doesn't add any instructions, does it?
Run Code Online (Sandbox Code Playgroud)

Mar*_*som 46

你是绝对正确的,空宏不会生成任何代码.

我见过两个有用的地方.第一种是在不使用函数参数时消除警告:

#define UNUSED(x)

int foo(int UNUSED(value))
{
    return 42;
}
Run Code Online (Sandbox Code Playgroud)

第二种是当你使用条件来确定是否应该有代码时.

#ifdef LOGGING_ENABLED
#define LOG(x) log_message(x)
#else
#define LOG(x)
#endif
Run Code Online (Sandbox Code Playgroud)

  • @GrijeshChauhan,你刚刚发现了C和C++之间的一个区别.见这里:http://codepad.org/flX8m3sk (3认同)

Gam*_*per 19

你的代码不完全正确,我建议你在宏中添加空括号

#define somemacro(a) {}
Run Code Online (Sandbox Code Playgroud)

原因很简单,你的代码会更安全!

举个例子:

if(Value)
    somemacro(a)
else
    somemacro(b)
Run Code Online (Sandbox Code Playgroud)

如果宏为空,则代码将无法编译!(在"else"之前的预期主要表达).无论如何某些风格规则迫使你写

if(Value)
{
    somemacro(a)
}
else
{
    somemacro(a)
}
Run Code Online (Sandbox Code Playgroud)

这样不会有问题.

另一种选择是使用";" 而不是"{}",但在相同的情况下,该选项将给你编译时警告,而空括号不会给出警告或错误!(即使发出警告,分号仍然更好);)

采取以下案例

if(value)
    somemacro(a);
else
    somemacro(b);
Run Code Online (Sandbox Code Playgroud)

将扩大到

if(value)
{};
else
{};
Run Code Online (Sandbox Code Playgroud)

那不能编译!

这就是为什么宏是邪恶的

(因为宏是简单的文本替换,所以哑巴的规则应该是总是尝试手动替换代码并看看会发生什么,还有一些工具可以代替显示扩展代码的宏.)

还是猜想是否有一个完全安全的宏?是的它被称为"NOP"

#define somemacro(a) ((void)0)
Run Code Online (Sandbox Code Playgroud)

在任何情况下都可以工作(甚至编译器的源文件也使用它作为NOP,例如只看"assert.h")

  • 确切的意图是显示最正确的宏用法.在某些情况下仍然无法使用空函数宏.因此,任何阅读你发布的随机用户都必须意识到使用"((void)0)"是更好的选择.无论如何,这是一个"NOP"而不是NOP.实际上没有为((void)0)生成额外的程序集,而NOP指令仍然是汇编代码.应始终考虑代码的安全性.无论如何仍然没有理由大拇指向下. (4认同)
  • 赞成,因为这是唯一关心滥用的答案——尽管重点可能应该直接放在 ((void) 0) 上。对于那些说这是不必要的(@Qix),请查看 [GCC 手册](https://gcc.gnu.org/onlinedocs/cpp/Macro-Pitfalls.html#Macro-Pitfalls)。 (2认同)
  • 嗯......这正是`do {} while(0)`idiom for.为此目的使用普通的`{}`并不是一个好主意,因为它要求用户记住在宏调用之后不要放置`;`. (2认同)

Cod*_*ray 6

预处理器对所有宏执行文字替换.

因此,如果您定义一个"空"宏,那么在编译器运行之前,预编译器将使用空语句替换标识符中出现的每个位置.

是的 不会为您的问题中给出的示例生成代码.


Gre*_*ill 6

那是对的.您的代码扩展为

;
Run Code Online (Sandbox Code Playgroud)

经过预处理.

请注意,您可以要求编译器预处理向您显示代码(在gcc中,这是-E选项;您的编译器可能会有所不同).

  • @shinkou,分号在宏之外,所以它应该是最终代码的一部分. (5认同)