【问题标题】: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

【问题讨论】:

标签: c++ visual-c++ macros variadic-macros


【解决方案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() 扩展为 1
PP_NARG(x) 扩展为 1
PP_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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-19
    • 2016-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多