可变宏参数计数未按预期工作
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()
扩展为 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
【讨论】:
以上是关于可变宏参数计数未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章