可变宏参数计数未按预期工作

Posted

技术标签:

【中文标题】可变宏参数计数未按预期工作【英文标题】:Variadic macro argument count not working as expected 【发布时间】:2017-08-20 22:11:09 【问题描述】:

所以,基本上我正在尝试实现一个宏来计算 VA_ARGS 中的参数数量。

为简单起见,它最多只能使用 3 个参数。问题是当宏使用少于3个参数时,它不起作用,并触发“expected an expression”错误。

#define EXPAND( x ) x
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, PP_RSEQ_N()))
#define PP_ARG_N(_1, _2, _3, N,...) N
#define PP_RSEQ_N() 3,2,1,0

void main()

    printf("\nTEST PP_NARG: %i", PP_NARG());        //Doesn't work (in this case it shouldn't work, so it's correct)
    printf("\nTEST PP_NARG: %i", PP_NARG(0));       //Doesn't work
    printf("\nTEST PP_NARG: %i", PP_NARG(0,0));     //Doesn't work
    printf("\nTEST PP_NARG: %i", PP_NARG(0,0,0));   //Works

只保留可以正确编译并打印“TEST PP_NARG: 3”的行。

我认为问题可能在于 PP_RSEQ_N() 仅扩展为“3”,而不是“3,2,1,0”,因为即使 PP_RSEQ_N() 被定义为这样

#define PP_RSEQ_N() 10,9,8,7,6,5,4,3,2,1,0

它仍然不能使用少于 3 个参数。

我正在使用 MSVC 编译器,这可能是导致问题的原因,因为它在使用宏时表现不佳,如下所示:MSVC doesn't expand __VA_ARGS__ correctly

【问题讨论】:

经典宏滥用示例。 #define PP_ARG_N2(...) PP_ARG_N(__VA_ARGS__)? 这是另一个尝试MSVC++ variadic macro expansion 【参考方案1】:

在您的实现中,PP_RSEQ_N()PP_ARG_N 的参数。作为一个参数,它仅在预处理的 参数替换 阶段进行扩展,但这仅发生在替换其替换列表中的参数之前(只要在替换列表中,它不是字符串化并且不参与粘贴)。

由于PP_ARG_N 在其替换列表中只有第四个参数N,因此PP_RSEQ_N() 只会在您碰巧传入三个参数时扩展。(在重新扫描和替换过程中会进行第二次扫描 阶段,在参数替换后应用...但这里没有效果,因为在调用中提到了PP_RSEQ_N()

去掉这个宏,像这样把它放在PP_NARG中:

#define EXPAND( x ) x
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, 3,2,1,0))
#define PP_ARG_N(_1, _2, _3, N,...) N

...一切正常“工作”:

PP_NARG() 扩展为 1PP_NARG(x) 扩展为 1PP_NARG(x,y) 扩展为 2

但是请注意,PP_NARG() 不会给您 0。可以说这实际上是正确的;对于预处理器,这不是传递零参数。它传递了一个只是空的参数。这与#define X(A) OPEN A CLOSE/X() 产生OPEN CLOSE 相同。如果出于某种原因您希望将其扩展为 0,则可能需要一些麻烦才能实现,但对于这个答案,我只专注于让您克服这一困难。

【讨论】:

这不仅仅是微软——它是 C 规范所规定的:当一个带有参数的宏被识别时,宏参数是基于直接输入令牌流收集的,没有宏扩展(然而)。参数中的宏将在收集参数后展开,然后再替换到正文中。【参考方案2】:

here 可以找到PP_ARG_N() 实现,它也可以区分带参数和不带参数的调用(感谢Scott Morrison)。对您的小程序的回应:

TEST PP_NARG: 0
TEST PP_NARG: 1
TEST PP_NARG: 2
TEST PP_NARG: 3

【讨论】:

以上是关于可变宏参数计数未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

随机算法未按预期运行

iOS:到 NSArray 的 JSON 字符串未按预期工作

NSM 可变数据。为啥保留计数 1 比我预期的要高?

LibreOffice 对话框未按预期工作

级联参数未按预期工作

我的音频和搜索功能未按预期运行