3

我需要在 C 中编写一个可变参数宏,它必须接受零个或多个参数。

在 gcc 中,这可以通过在逗号后添加“##”来实现,例如,##____VA_ARGS____Variadic macros with zero arguments中回答。

但是,我的构建系统中的编译器(超出我的控制范围)不理解,##语法,因此不会吞下逗号。

有我可以使用的解决方法吗?

谢谢!

4

2 回答 2

4

是的,gcc 吞下逗号是非标准的,你不应该依赖它。

使用符合 C99 的预处理器,您可以通过测试作为空标记的宏参数来实现类似的效果。有关其工作原理的想法,您可以在此处查看,对于简化此类功能的编程的一整套预处理器宏,请参阅P99

于 2011-12-09T12:43:08.893 回答
1

使用Jens 所阐述的简化版本,下面描述了一种可能的方法。

E_用于注入参数,而I_用于引起宏的间接调用。V_需要添加额外的间接级别,这对于某些编译器来说似乎是必需的。

#define V_(...) __VA_ARGS__
#define I_(M,...) V_(M(__VA_ARGS__))
#define E_() _,

现在,假设您需要一个宏MAC来处理 0、1 或 2 个参数:

MAC(1, 2);
MAC(1);
MAC();

一种可能的实现可能如下所示:

#define MAC_X(_2,_1,X,...) MAC_##X
#define MAC(...) V_(V_(MAC_X(__VA_ARGS__,2,_))(__VA_ARGS__))

#define MAC_2(...) function_for_2(__VA_ARGS__)
#define MAC_1(...) function_for_1(__VA_ARGS__)
#define MAC_0(...) function_for_0(__VA_ARGS__)

#define MAC_Y(_1,Y,...) MAC_##Y
#define MAC__(...) I_(MAC_Y, E_ __VA_ARGS__ () 0, 1)(__VA_ARGS__)

将其扩展为 3 个参数相对简单。唯一的混乱是检测 1 或 0 个参数,这不会改变:

-#define MAC_X(_2,_1,X,...) MAC_##X
-#define MAC(...) V_(V_(MAC_X(__VA_ARGS__,2,_))(__VA_ARGS__))
+#define MAC_X(_3,_2,_1,X,...) MAC_##X
+#define MAC(...) V_(V_(MAC_X(__VA_ARGS__,3,2,_))(__VA_ARGS__))

+#define MAC_3(...) function_for_3(__VA_ARGS__)
 #define MAC_2(...) function_for_2(__VA_ARGS__)

对于超过 1 个参数,MAC宏扩展为MAC_2(或MAC_3)。但是,对于 1 或 0 个参数,MAC宏扩展为MAC__.

MAC__宏应用 Jens 的技巧来检测是否传递了 1 个或 0 个参数。它使用E_辅助宏执行此操作,并在 和 之间注入其参数E_()这将导致它被调用。如果有 0 个参数,E_则调用 并注入一个参数。注入的参数导致0成为选择的第二个参数MAC_Y。如果有 1 个参数,E_则不展开。to 的第一个参数MAC_Y变为E_ ... () 0(其中...第一个参数是什么),第二个参数为MAC_Yis 1。这允许MAC_Y调用MAC_0MAC_1

于 2020-01-15T00:52:42.740 回答