具有两个命名参数的C可变参数宏

时间:2018-12-30 16:45:15

标签: c c-preprocessor

我想使用可变参数宏,但是它似乎仅设计为专门处理第一个参数。我希望前两个参数被命名,其余的不被命名,像这样:

#define FOO(AA,BB,...) AA->BB(AA,##...)

FOO(mystruct,funcname,123)

但是,这不适用于LLVM。我是在做错什么,还是可变参数宏的工作方式受到限制?


更新

正确的答案是,使用## VA_ARGS 代替## ...

有些网页声称“ ...”有效,但至少对于MacOS llvm无效。

2 个答案:

答案 0 :(得分:1)

宏参数不会在宏扩展中使用...进行扩展-怎么可能,因为那样的话,您将无法在扩展中使用使用省略号的宏。相反,它将作为特殊参数__VA_ARGS__可用。

有了这个,下面的程序

#define FOO(AA,BB,...) AA->BB(AA, __VA_ARGS__)

FOO(mystruct,funcname,123)
FOO(mystruct,funcname,123,456)

will be preprocessed to


##是粘贴令牌的运算符。它将由2个部分组成一个预处理令牌。 , ## ...尝试制作预处理令牌,...。这不是有效的C令牌,这就是Clang会报告的原因

<source>:3:1: error: pasting formed ',...', an invalid preprocessing token 

答案 1 :(得分:1)

...宏参数通过__VA_ARGS__粘贴到宏体中。 问题是如何允许它为空。 如果为空,则通常需要先擦除逗号,然后再 您可以使用GNU ##__VA_ARGS__扩展名来实现。

#define FOO(AA,BB,...) AA->BB(AA,##__VA_ARGS__) /*GNU extension*/
FOO(mystruct,funcname) //warning with -pedantic
FOO(mystruct,funcname,123)

但是,如果使用-pedantic进行编译,以上内容将触发警告。 如果您希望宏在-pedantic时不加警告地可用,则可以通过交换宏定义中的前两个参数来实现。

#define FIRST(...)  FIRST_(__VA_ARGS__,)
#define FIRST_(X,...) X
#define BAR_(CallExpr,...) CallExpr(__VA_ARGS__)
#define BAR(BB,/*AA,*/...) BAR_(FIRST(__VA_ARGS__)->BB,__VA_ARGS__)

BAR(funcname,mystruct) //no warning
BAR(funcname,mystruct,123)