【问题标题】:Preprocessor macros as parameters to other macros预处理器宏作为其他宏的参数
【发布时间】:2012-05-27 21:21:10
【问题描述】:

以下 C++ 代码编译并作为程序员在 GCC (4.0.4) 上运行

#define FOO(x,y,z) ((x)*(y)*(z))
#define BAR(x) FOO(x,1)
#define BAZ 3,7

int main()
{
    return BAR(BAZ); /* interpreted as return ((3)*(7)*(1)); */
}

但是,宏在 Microsoft Visual C++ Express 2010 上会导致错误:

main.cpp(7):警告 C4003:宏 'FOO' 的实际参数不足
main.cpp(7):错误 C2059:语法错误:')'

问题似乎在于,Microsoft 编译器在内部处理 BAR 宏时,并未将 BAZ 宏扩展为可用作宏 FOO 的两个单独参数的参数。

按照标准,哪个编译器能正确处理这种情况?

【问题讨论】:

  • 看来你真正要找的是variadic macros
  • @leftaroundabout 好像他不是……
  • @iammilind:标准第 16 章缺少什么?它怎么不是一个“真正的”标准?
  • @iammilind 当然可以。它旨在允许在实现中留出一些余地,并且某些涉及令牌粘贴的操作会导致未定义的行为,但这里不是这种情况。 (通常,在存在未定义行为的情况下,g++ 会发出错误信号,而大多数其他编译器都会接受它。)
  • @CharlesBaily,你是对的。删除 cmets(登录 PC 后)。

标签: c++ macros c-preprocessor legacy-code visual-studio-macros


【解决方案1】:

根据 ISO/IEC 14882:2003 (C++ Stardard) 16.3.4 的宏扩展执行如下:

  1. 宏调用被宏的替换列表(主体)替换,其中每个参数名称(除非它受 # 或 ## 影响)被宏调用中指定的相应参数的完整宏扩展替换。
  2. 第 1 步的结果被重新扫描。如果其中有更多的宏调用(除了那些已经扩展的正在考虑的文本),它们会根据相同的过程递归地扩展。

您指定的代码的步骤顺序是:

  1. BAR(BAZ)
  2. FOO(3,7,1)
  3. ((3)*(7)*(1))

所以 GCC 是对的,而 VC 不是。但是 VC 抱怨的错误是 FOO 有 3 个参数,而 BAR 只指定了其中的 2 个。 VC 显然试图尽快捕捉错误,但做得有点过火了。

【讨论】:

  • 我不明白您给出的算法如何与 GCC 行为相对应。如果我没看错的话,算法如下:BAR(BAZ) 是对BAR 的调用,参数为BAZ,因此被FOO(BAZ,1) 替换。这现在被重新扫描。它找到的第一个宏是FOO,所以现在它尝试使用参数BAZ1 扩展FOO。这没有足够的参数,所以预处理失败。为什么重新扫描FOO(BAZ,1)会先扩展BAZ,而扫描BAR(BAZ)会先扩展BAR
  • 感谢您清晰完整的解释。我学到了很多。
猜你喜欢
  • 1970-01-01
  • 2017-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-31
  • 2011-05-14
  • 2015-04-15
相关资源
最近更新 更多