Cil*_*yan 4 c macros gcc visual-c++ language-lawyer
我正在处理的代码使用一些非常复杂的宏voodoo来生成代码,但最后有一个看起来像这样的构造
#define ARGS 1,2,3
#define MACROFUNC_OUTER(PARAMS) MACROFUNC_INNER(PARAMS)
#define MACROFUNC_INNER(A,B,C) A + B + C
int a = MACROFUNC_OUTER(ARGS);
Run Code Online (Sandbox Code Playgroud)
期待的是获得
int a = 1 + 2 + 3;
Run Code Online (Sandbox Code Playgroud)
这适用于最初为GHS编写的编译器以及GCC编写的编译器,但MSVC(2008)认为PARAMS
它不会扩展为单个预处理令牌,然后A
将其设置为整体PARAM
,B
而C
不是任何内容.结果就是这样
int a = 1,2,3 + + ;
Run Code Online (Sandbox Code Playgroud)
虽然MSVC警告说not enough actual parameters for macro 'MACROFUNC_INNER'
.
MSVC不符合要求.该标准实际上是明确的,虽然它不觉得有必要提到这个特殊情况,这并不例外.
遇到类似函数的宏调用时,预处理器:
§6.10.3/ 11标识了参数,这些参数可能是由非受保护逗号分隔的标记的空序列,(如果逗号在括号内,则受到保护()).
§6.10.3.1/ 1对宏体进行了第一次传递,用相应的完全宏扩展参数替换了一个#
或者没有在一个或多个##
操作中使用的参数.(在此步骤中,宏体中没有其他替换.)
§6.10.3.4/ 1重新扫描替换的替换标记序列,根据需要执行更多宏替换.
(以上几乎忽略了stringification(#
)和token concatenation(##
),这与这个问题无关.)
这种操作顺序明确地导致了编写软件的人所期望的行为.
显然(根据@dxiv,并在此处验证)以下符合标准的解决方法适用于某些版本的MS Visual Studio:
#define CALL(A,B) A B
#define OUTER(PARAM) CALL(INNER,(PARAM))
#define INNER(A,B,C) whatever
Run Code Online (Sandbox Code Playgroud)
供参考,来自C11标准的实际语言,跳过引用#
和##
处理:
§6.10.311由最外部匹配括号限定的预处理标记序列形成类函数宏的参数列表.列表中的各个参数由逗号预处理标记分隔,但匹配内部括号之间的逗号预处理标记不会分隔参数....
§6.10.3.11在识别出类似函数宏的调用参数之后,进行参数替换.在扩展了包含在其中的所有宏之后,替换列表中的参数...被相应的参数替换.在被替换之前,每个参数的预处理标记都被完全宏替换,好像它们形成了预处理文件的其余部分......
§6.10.3.41替换列表中的所有参数都已被替换... [t]然后重新扫描生成的预处理标记序列以及源文件的所有后续预处理标记,以替换更多的宏名称.
归档时间: |
|
查看次数: |
2197 次 |
最近记录: |