【问题标题】:What happens with undefined macro parameters once compiled?编译后未定义的宏参数会发生什么?
【发布时间】:2018-07-20 21:59:09
【问题描述】:

在我的 VC++ 项目中,我使用宏进行调试和记录。

调用:

  Logger(LogLevel::Info, "logging started");

宏:

#ifdef DEBUG
    #define Logger(level, input) \
            { \
                cerr << "[" << level << "] " << input << endl; \
            };
#else
    #define Logger();
#endif

编译时我收到以下警告(但它仍然编译):

警告 C4002:宏 'Logger' 的实际参数过多

我想知道编译器如何处理这种情况。 宏参数是否仍用于编译?例如。逆向工程中能看到“logging started”字符串吗?

【问题讨论】:

  • 为什么不在#define中添加参数,然后不要在替换中使用它们?
  • @BenVoigt 这就是我目前所拥有的。我想知道这个描述的场景是如何工作的。也感谢您的反对。 SO 对新人来说很有趣。
  • @Thomas 它像往常一样通过纯文本替换解决了,并注明“特殊”。
  • 在#else 中只需执行#define Logger(level, input)。那将忽略参数。此外,要改掉在宏定义末尾添加分号的习惯。最后,您显示的“通话”使用的是Log 而不是Logger。
  • @Peter 我不能再编辑问题了。如果您查看编辑草稿,您会看到我将其更改为 Log。

标签: c++ visual-c++ c-preprocessor


【解决方案1】:

我想知道编译器如何处理这种情况。宏参数是否仍用于编译?

宏在预处理阶段进行处理。如果预处理器能够处理宏使用中使用的额外参数,那么它唯一能做的就是将这些参数放入宏扩展中。

例如在逆向工程中可以看到“logging started”字符串吗?

不,编译器处理的代码根本不会有那行。


如果您可以选择更改这些代码行,我建议将宏的非调试定义更改为 noop 扩展。例如:

#define Logger(level, input) (void)level; 

【讨论】:

  • 不知道 __noop,谢谢。我猜编译器在看到对 noop 函数的调用时会删除整个函数调用?
  • @Thomas,我不确定它是完全删除它还是留下一些执行足迹非常小的代码。
  • @R Sahu 根据stackoverflow.com/a/14459264/9279154,整个函数都不会被调用。也感谢您成为唯一真正回答问题的人。欣赏。
  • @Thomas,不幸的是,__noop 是 VS 中的非标准功能。如果您正在为其他平台编写代码,则不能依赖它。
  • “编译器”不会删除任何东西。编译过程(如标准中规定)首先发生预处理阶段(名义上由“预处理器”执行),然后该(预处理源)的输出被馈送到后续编译阶段(名义上由“编译器”执行”)。如果宏参数在预处理阶段扩展为空,它甚至在编译阶段都不存在,更不用说输出(例如输出到目标文件或可执行文件)。
【解决方案2】:

根据法律,宏函数必须声明与调用它一样多的参数。

所以调用你的宏

#define Logger()

Logger(LogLevel::Info, "logging started") 会导致错误。 MSVC 可能允许它,因为它不符合标准。没有什么可以进一步推理的(这是我对实际问题的回答)。

你也可以

#define Logger(unused,unused2)

并将替换部件留空或

#define Logger(...) 

并承受能够使用任意数量的参数调用的后果。 [提示:推荐第一个。]

【讨论】:

  • 而#define Logger(...) 假设您使用的是符合 C99 且支持可变参数宏的 C 预处理器。
  • 这不是错误。 MSVC 在这种情况下会发出警告,但仍会编译。
  • @Thomas 这并不意味着这是标准行为。其他三个编译器不同意并发出硬错误。
  • 接受无效代码并没有“不符合标准”:只要发出诊断消息,就完全满足标准要求。 C 和 C++ 都没有区分“错误”和“警告”。它们都只是诊断信息。在这个特定方面(即扩展的数量),MSVC 可能是市场上最“最符合标准”的编译器之一。
  • @Thomas:从某种意义上说,您的代码格式错误(我们通常称之为“错误”)是一个“错误”。但是,编译器不需要在遇到格式错误的代码时拒绝您的代码并停止编译。他们只需要以某种与实现相关的方式通知您有关问题的信息。他们可以给你一个有意义的信息。或者他们可以打印“喵!吠!”并继续编译。该标准不要求更多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 2010-09-06
  • 1970-01-01
相关资源
最近更新 更多