【问题标题】:How to expand variadic arguments in a macro?如何在宏中扩展可变参数?
【发布时间】:2012-12-21 22:28:45
【问题描述】:

我想拥有一个宏缩短器。

宏,FOO(A,B,C) 应该扩展为 defined(_FOO_A) || defined(_FOO_B) || defined(_FOO_C).

在 GCC 中是否可以使用可变参数宏参数而不是实际编写 3 个函数(FOO(A)FOO(A,B)FOO(A,B,C))?

【问题讨论】:

  • 以两个下划线或一个下划线和一个大写字母开头的标识符保留供语言实现使用。
  • 好像和efesx.com/2010/08/31/overloading-macrosefesx.com/2010/07/17/…很像,欢迎大家看看。
  • 通常情况下,我会说编写一个遍历参数并检查每个定义的循环......但是,如果在预处理器指令的上下文中使用定义,那就不行了。
  • 您提供的代码是您在一般情况下想要的示例,还是您需要该宏?
  • @CarlNorum:我同意。我只是提供了它作为示例并区分 FOO 和 _FOO。

标签: c gcc c-preprocessor c99 variadic-macros


【解决方案1】:

无法将宏扩展为包含 defined 关键字的内容:

如果令牌 defined 是作为此替换的结果生成的 defined 一元运算符的处理或使用与其中一个不匹配 宏替换之前的两个指定形式,行为是 未定义。

所以你不能用defined 做到这一点。如果您愿意通过仅测试 FOO_A_FOO_B_、...的值来放松该约束,则可以使用 P99 来做到这一点。例如,只做一个逻辑或变量列表将是

#if P99_ORS(A, B, C)
...
#endif

P99_ORS 表达式扩展到的位置

((((A) || (B))) || (C))

然后对#if 表达式求值。

如果您想做一些宏编程,也可以先将其扩展为您喜欢的令牌列表

#define P00_NAME_X(NAME, X, I) P99_PASTE2(NAME, X)
#define CONDITION(NAME, ...) P99_ORS(P99_FOR(FOO_, P99_NARG(__VA_ARGS__), P00_SEQ, P00_NAME_X, __VA_ARGS__))

这样

CONDITION(A, B, C, toto);

将扩展为

((((((FOO_A) || (FOO_B))) || (FOO_C))) || (FOO_toto));

【讨论】:

    【解决方案2】:

    这样的?

    #include <stdio.h>
    
    #define FOO(A, B, C) (FOO_X(A) || FOO_X(B) || FOO_X(C))
    #define FOO_X(x) defined(_FOO_##x)
    
    // just to print it
    #define QUOTE(...) QUOTE_AUX(__VA_ARGS__)
    #define QUOTE_AUX(...) #__VA_ARGS__
    
    int main(void)
    {
        puts(QUOTE(FOO(a, b, c)));
    }
    

    EDIT:实际上这会导致所有 C 标准中的未定义行为

    【讨论】:

    • 不幸的是,这是标准禁止的。 define 不允许出现在宏展开中。
    猜你喜欢
    • 1970-01-01
    • 2012-02-29
    • 2019-09-23
    • 2020-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多