我需要在 C 中编写一个可变参数宏,它必须接受零个或多个参数。
在 gcc 中,这可以通过在逗号后添加“##”来实现,例如,##____VA_ARGS____
在Variadic macros with zero arguments中回答。
但是,我的构建系统中的编译器(超出我的控制范围)不理解,##
语法,因此不会吞下逗号。
有我可以使用的解决方法吗?
谢谢!
使用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_Y
is 1
。这允许MAC_Y
调用MAC_0
或MAC_1
。