考虑以下代码
#define COMB(F, ...) F(__VA_ARGS__)
#define ADD(X, Y) (X + Y)
int foo() {
return COMB(ADD, 1, 2);
}
我已经在Godbolt上做了一些实验。 Microsoft VS v19.22(带有/ E标志)在预处理宏时失败。它给出以下错误
int foo() {
return (1, 2 + );
}
example.cpp
<source>(8): warning C4003: not enough arguments for function-like macro invocation 'ADD'
GCC(带有-E标志)仅按预期输出
int foo() {
return (1 + 2);
}
我看了C99标准。但是我仍然不确定哪个编译器在正确执行?
我希望有人可以帮助我澄清这一点。
我认为gcc是正确的。尽管C11 6.10.3 / 12将COMB的调用描述为具有两个自变量(ADD
和1,2
),但一旦扩展了COMB
,则生成的令牌序列为ADD
(
1
,
2
)
和6.10.3.4/1清楚地表明,第一次替换的结果已重新扫描为预处理令牌序列。上一步中包含多个令牌的参数并没有以某种方式粘贴到单个令牌中以进行重新扫描。
6.10.3.4/1:
在替换列表中的所有参数都被替换并且#和##处理已经完成,所有的地标预处理令牌均已删除。 然后重新扫描生成的预处理令牌序列,以及所有后续的源文件的预处理令牌,以便替换更多的宏名称
MSVC将__VA_ARGS__
传递到宏后将其展开。您必须像这样手动扩展宏:
#define EXPAND(x) x
#define COMB(F, ...) EXPAND(F(__VA_ARGS__))
#define ADD(X, Y) (X + Y)
在这种情况下,GCC是正确的编译器。