【问题标题】:##__VA_ARGS__ not swallowing comma when zero args under C99##__VA_ARGS__ 在 C99 下零参数时不吞下逗号
【发布时间】:2016-05-13 09:22:13
【问题描述】:

我想使用如下宏:

#define x(...) y(a,##__VA_ARGS__,b)

像这样展开:

x();   ->   y(a,b);
x(1);  ->   y(a,1,b);

使用-std=gnu99,它可以完美运行。

然而,使用-std=c99,它看起来像这样:

x();   ->   y(a,,b);
x(1);  ->   y(a,1,b);

## 没有任何区别——它没有吞下逗号。

在 C99 下的其他用法中,例如#define x(a,...) y(a,##__VA_ARGS__),逗号吞咽没问题。

如果有的话,我该怎么做才能在 clang 的 -std=c99 下获得所需的逗号吞咽行为,无论是使用 GNU 扩展 ## 还是通过其他方法?

【问题讨论】:

  • 那么这在实现方面是如何工作的(即函数如何使用变量参数)?
  • @trojanfoe 感谢您的评论,但这不在此问题的范围内。 (这不是一个 XY 问题。)
  • @trojanfoe 当然:如果没有参数,我正在使用此宏调用 a(),如果有一个参数,我正在使用此宏调用 b(x)GET_MACRO(_0, ##__VA_ARGS__, b, a)(__VA_ARGS__)

标签: c macros c-preprocessor variadic-macros


【解决方案1】:

这是预期的行为。没有标准的方式来吞下逗号。

幸运的是,gccclangxlc 支持 ##__VA_ARGS__ gnu 扩展,msvc 会自动吞下逗号。

如果您不想依赖上述语言扩展,惯用的 ISO C90 获取可变参数宏的方法如下:

#define x(args) y args

/* notice the extra parantheses */
x((a, b, c, d));

如果您不想使用这两种解决方案中的任何一种,您可以随时使用参数计数,如 here 的回答。

【讨论】:

    【解决方案2】:

    是的,##__VA_ARGS__ 是一个 GNU 扩展。

    【讨论】:

    • 查看我的问题:“在 C99 下的其他用法中,例如 #define x(a,...) y(a,##__VA_ARGS__),逗号吞咽工作正常。”
    • 另外,我问是否有任何方法,使用##__VA_ARGS__ 与否。
    • 刚刚用std=c99 -pedantic 尝试了clang,#define x(a,...) y(a,##__VA_ARGS__) 行给出了警告Token pasting of ',' and __VA_ARGS__ is a GNU extension。所以我认为在 C99 下获得逗号吞咽行为是特定于您的编译器/命令行参数的。它不是标准的 C99。
    • 对不起,我应该更清楚。我知道这不是标准的 C99。我正在寻找一种符合 C99 的可行方式,或者我可以利用 gcc/clang 的 -stc=c99 加上 ## 来做到这一点。
    • 我认为以符合 C99 或 C11 的方式执行此操作的唯一方法是在宏调用中包含逗号,即#define x(...) y(a __VA_ARGS__,b),所以x(,) --> y(a,b),和x(,1) --> y(a,1,b)。或者您可以稍微不同地定义x,以便在参数列表的末尾使用额外的逗号而不是参数列表的开头来调用它。无论哪种方式都同样丑陋,并不是你想要的。您可以使用 GCC 扩展,也可以等待 C 标准的新修订版,这可能会或可能不会定义吞下逗号的标准方式!
    【解决方案3】:

    正如您所描述的,以下模式可以正常工作。

    #define x(a,...) y(a,##__VA_ARGS__)
    

    运行以下代码片段后,我猜##__VA_ARGS__ 在前缀 args 存在时总是会吞下逗号(例如 e_x 中的 _)

    #define x(...) y(a,c, ##__VA_ARGS__, b)
    #define e_x(_, ...) y(a, c, ##__VA_ARGS__, b)
    
    x();
    x(a);
    x(a, b);
    
    e_x();
    e_x(a);
    e_x(a, b);
    

    你可以得到结果:

    y(a,c,, b);
    y(a,c,a, b);
    y(a,c,a, b, b);
    
    y(a, c, b);
    y(a, c, b);
    y(a, c, b, b);
    

    上面的示例在我的电脑上运行良好(macos 和 linux)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多