【问题标题】:Can I define variadic C preprocessor macros with __VA_ARGS in the middle instead of the end?我可以用 __VA_ARGS 在中间而不是结尾定义可变参数 C 预处理器宏吗?
【发布时间】:2011-04-20 12:12:35
【问题描述】:

如果我这样做,GCC 会抱怨:

#define M(obj,met, ..., contents) obj##_##met(const void * self, __VA_ARGS__) { \
   contents \
   }

给我这两个原因:

error: missing ')' in macro parameter list
warning: __VA_ARGS__ can only appear in the expansion of a C99 variadic macro

显然,C99 风格的可变参数宏期望在省略号之后立即有右括号,有效地要求可变参数列表是宏的最后一个参数。我需要它位于中间以生成上述宏中描述的速记符号。 GCC 是否支持此功能,使用另一种(非 C99)可变参数宏样式?我可以以其他方式模仿它吗?我不希望最后的可变参数列表,它会使我的符号混乱。而且我只能使用 GCC。

【问题讨论】:

  • 我不希望最后的可变参数列表,它会使我的符号混乱。而且我只能使用 GCC。 你不走运。
  • 查看Boost.Preprocessor。我几乎可以肯定,只要您停止尝试将 content 识别为单独的参数,您就可以做到 - 您使用预处理器的一部分来识别变量参数的最后一个参数。当然,定义要复杂一些。

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


【解决方案1】:

你必须把...放在最后,但是使用LASTPOP_LAST宏,你可以为你的宏保持相同的参数顺序并像这样定义它:

#define M(obj,met, ...) obj##_##met(const void * self, POP_LAST(__VA_ARGS__)) { \
   LAST(__VA_ARGS__) \
   }

以下是如何定义这些宏:

/* This counts the number of args */
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)

/* This will let macros expand before concating them */
#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)

/* This will pop the last argument off */
#define POP_LAST(...) CAT(POP_LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__)
#define POP_LAST_1(x1)
#define POP_LAST_2(x1, x2) x1
#define POP_LAST_3(x1, x2, x3) x1, x2
#define POP_LAST_4(x1, x2, x3, x4) x1, x2, x3
#define POP_LAST_5(x1, x2, x3, x4, x5) x1, x2, x3, x4
#define POP_LAST_6(x1, x2, x3, x4, x5, x6) x1, x2, x3, x4, x5
#define POP_LAST_7(x1, x2, x3, x4, x5, x6, x7) x1, x2, x3, x4, x5, x6
#define POP_LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x1, x2, x3, x4, x5, x6, x7

/* This will return the last argument */
#define LAST(...) CAT(LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__)
#define LAST_1(x1) x1
#define LAST_2(x1, x2) x2
#define LAST_3(x1, x2, x3) x3
#define LAST_4(x1, x2, x3, x4) x4
#define LAST_5(x1, x2, x3, x4, x5) x5
#define LAST_6(x1, x2, x3, x4, x5, x6) x6
#define LAST_7(x1, x2, x3, x4, x5, x6, x7) x7
#define LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x8

这些宏最多可用于 8 个参数。如果您愿意,可以轻松扩展它们以处理更多内容。

【讨论】:

    【解决方案2】:

    不,你不能。 ... 必须出现在末尾。

    但您可以将M 定义为

    #define M(obj,met, ...) obj##_##met(const void * self, __VA_ARGS__)
    

    并将其用作

    void M(foo, bar, int x, char y, double z) {
       content;
    }
    

    【讨论】:

    • :( 这就是我所担心的。谢谢 :D
    猜你喜欢
    • 2013-03-14
    • 2015-07-12
    • 2015-01-18
    • 2011-05-31
    • 2012-02-21
    • 2018-12-27
    • 2010-10-23
    • 2010-09-23
    • 2011-01-26
    相关资源
    最近更新 更多