c++ - 使用 gcc 和 clang 的可变宏扩展的奇怪行为

标签 c++ gcc clang variadic-macros

我正在用 C++ 编写可变参数调度程序宏,以根据提供给调度程序的参数数量(从无到 5)调用不同的宏。我想出了这个解决方案:

#define GETOVERRIDE(_ignored, _1, _2, _3, _4, _5, NAME, ...) NAME
#define NAMEDARGS(...) GETOVERRIDE(ignored, ##__VA_ARGS__, NAMEDARGS5, NAMEDARGS4, NAMEDARGS3, NAMEDARGS2, NAMEDARGS1, NAMEDARGS0)(__VA_ARGS__)

NAMEDARGS 是调度器宏;使用 1 个参数调用它会导致调用带有 1 个参数的 NAMEDARGS1,依此类推(我不提供各种 NAMEDARGS# 的实现,因为它们与此上下文无关)。

我测试了 gcc 7.1.1 代码,发现使用 -std=c++14 标志时 gcc 扩展有一个奇怪的行为。使用此测试代码:

NAMEDARGS()
NAMEDARGS(int)
NAMEDARGS(int, float)

我得到了这些扩展:

$ gcc -E testMacro.cpp
NAMEDARGS0()
NAMEDARGS1(int)
NAMEDARGS2(int, float)

$ gcc -E -std=c++14 testMacro.cpp
NAMEDARGS1()
NAMEDARGS1(int)
NAMEDARGS2(int, float)

似乎使用 -std=c++14 标志替换零参数调用失败,导致调用单参数宏。我认为这可能是因为 ##__VA_ARGS__ 语法是 GNU 扩展,因此不适用于 ISO C++ 预处理器;但是,当尝试使用 clang 4.0.1 时,我获得了所需的扩展:

$ clang -E -std=c++14 testMacro.cpp
NAMEDARGS0()
NAMEDARGS1(int)
NAMEDARGS2(int, float)

所以我不明白这里发生了什么。 clang 是否实现了这个 gnu 扩展,接受非 ISO 代码也与 -std==c++14 不同 gcc?或者也许问题出在其他地方?感谢您的帮助。

最佳答案

GCC 默认 -stdgnu++14(参见 here ),这是带有 GNU 扩展的 C++14。

将两者与仅定义的 NAMEDARGS(...) 进行比较显示了扩展的不同之处:

代码

#define NAMEDARGS(...) GETOVERRIDE(ignored, ##__VA_ARGS__, NAMEDARGS5, NAMEDARGS4, NAMEDARGS3, NAMEDARGS2, NAMEDARGS1, NAMEDARGS0)(__VA_ARGS__)
NAMEDARGS()

-std=gnu++14 -E

GETOVERRIDE(ignored, NAMEDARGS5, NAMEDARGS4, NAMEDARGS3, NAMEDARGS2, NAMEDARGS1, NAMEDARGS0)()
-------------------^

-std=c++14 -E

GETOVERRIDE(ignored,, NAMEDARGS5, NAMEDARGS4, NAMEDARGS3, NAMEDARGS2, NAMEDARGS1, NAMEDARGS0)()
-------------------^^

我不是一个有经验的标准读者,但我在 [cpp.replace] 中发现了以下两段,这表明 GCC 在这两个调用中都是正确的:

If the identifier-list in the macro definition does not end with an ellipsis, the number of arguments (including those arguments consisting of no preprocessing tokens) in an invocation of a function-like macro shall equal the number of parameters in the macro definition. Otherwise, there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...). There shall exist a ) preprocessing token that terminates the invocation.

...

If there is a ... immediately preceding the ) in the function-like macro definition, then the trailing arguments, including any separating comma preprocessing tokens, are merged to form a single item: the variable arguments. The number of arguments so combined is such that, following merger, the number of arguments is one more than the number of parameters in the macro definition (excluding the ...).

那么空的 __VA_ARGS__ 被扩展为一个空的参数似乎是正确的。

我找不到clang在这里的行为是否有意。

关于c++ - 使用 gcc 和 clang 的可变宏扩展的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45456842/

相关文章:

c++ - C++ 中的二维(或多维)动态创建数组

c++ - 插入 vector

当我使用 GNU C 库提供的非标准函数时,Clang 会警告我吗?

c++ - 奇怪的双重自由腐败(GCC 4.9.2,Ubuntu Vivid 上的 Clang3.6)

c++ - IP 地址重叠/在 CIDR 范围内

c++ - fstream open() Mac OS X 中的相对路径不起作用

c++ - 无法在 Apache Ignite 中安装 ODBC 驱动程序 C++

c - 关于C语言在GCC、Linux环境下的指针

c - 使用#define定义和#if defined查看是否定义

c - 如何将 libc_nano 与 Clang 一起使用?