【问题标题】:Why does a variadic macro give me an error?为什么可变参数宏会给我一个错误?
【发布时间】:2018-10-02 09:39:29
【问题描述】:

鉴于此示例代码:

#define vX(a, ...) ((a)(__VA_ARGS__) ? 1 : 0)

{
    int f();
    vX(f);
}

我收到error C2155: '?': invalid left operand, expected arithmetic or pointer type

另一方面,如果我为宏提供第二个参数,它会编译 fin - 例如:

vX(f,1)

没问题。我正在用 msvc 编译器编译 C 代码。

很抱歉打扰大家,但错误在我这边 - 给我错误的 2 个函数不仅没有参数,而且返回类型也为 void - 这导致了我的问题,而不是任何与宏相关的问题。

【问题讨论】:

  • 如果在{ 之前添加int main(),它可以在我的Visual Studio 2017 上正常编译。你使用什么版本的VS?
  • 这是一个相当复杂的问题,这里讨论了一个 gcc 非标准扩展作为解决方案:stackoverflow.com/questions/5891221/…。更多信息和宏诡计:gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments
  • 这个问题缺少一些东西。填写完整程序的最小正确语法,这在 VS 10.0 和 VS 12.0 中编译得很好。当前的答案虽然还可以(您的宏不符合 CPP 的标准),但似乎忽略了您似乎是在使用 MSVS 进行编译的事实(由您收到的错误指示)。

标签: c visual-c++ variadic-macros


【解决方案1】:

来自GCC documentation

当宏被调用时,它的参数列表中最后一个命名参数(这个宏没有)之后的所有标记,包括任何逗号,都成为变量参数。此标记序列将替换宏正文中出现的标识符__VA_ARGS__

所以,基本上__VA_ARGS__ 部分不能为空,这需要 GNU 扩展 (__VA_OPT__)。

【讨论】:

    【解决方案2】:

    预处理器对此的规范有些冗长,但只要说您指定vX 必须至少接受两个参数就足够了。

    原因是参数的数量很大程度上取决于宏中逗号的数量。因此,例如vX(f,) 也会导致您的错误消失。原因是我们再次提供了两个参数,即f 和逗号后的空标记序列。

    绕过它的一个技巧是将宏拆分为两个扩展:

    #define vX_(a, ...) ((a)(__VA_ARGS__) ? 1 : 0)
    #define vX(...) vX_(__VA_ARGS__,)
    

    注意我是如何添加逗号的?现在,当您编写 vX(f) 时,它将扩展为 vX_(f,),它将再次扩展以提供您想要的表达式。虽然,这在一般情况下不起作用,因为你会得到一个尾随逗号。这就是为什么 GCC 引入了__VA_OPT__ (@unwind's answer),以便可以有条件地添加逗号。

    【讨论】:

    • 这仅在您将一个参数传递给 vX 时才有效,这有点违背 ... 的目的,你不觉得吗?
    • @n.m. - 我把它归咎于宏是一个粗糙的工具。你可以有一个或另一个。但我确实告诉 OP 它一般不会起作用,所以......是的。
    • 宏很粗糙,但 OP 的原始宏对我来说很好。
    • @n.m. -It produces a warning under -pedantic。 GCC 接受它是另一个扩展。从技术上讲,它的格式不正确。
    • 不知道写这部分标准的人是否熟悉零的概念。
    猜你喜欢
    • 2013-11-14
    • 1970-01-01
    • 1970-01-01
    • 2021-04-02
    • 2021-11-19
    • 2022-01-05
    • 2021-08-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多