可变宏参数计数未按预期工作
Variadic macro argument count not working as expected
所以,基本上我正在尝试实现一个宏来计算 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
在您的实现中,PP_RSEQ_N()
是 PP_ARG_N
的参数。作为参数,它仅在预处理的 argument substitution 阶段进行扩展,但这只会在替换其替换列表中的参数之前发生(只要在替换列表中,它没有被字符串化,也没有参与粘贴。
由于 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
...还有事情 "work" 很好:
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,可能需要一些技巧才能实现它,但对于这个答案,我只专注于让你度过这个难关。
可以找到一个 PP_ARG_N()
实现,它也可以区分带参数和不带参数的调用 here (kudos to Scott Morrison)。对你的小程序的回应:
TEST PP_NARG: 0
TEST PP_NARG: 1
TEST PP_NARG: 2
TEST PP_NARG: 3
所以,基本上我正在尝试实现一个宏来计算 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
在您的实现中,PP_RSEQ_N()
是 PP_ARG_N
的参数。作为参数,它仅在预处理的 argument substitution 阶段进行扩展,但这只会在替换其替换列表中的参数之前发生(只要在替换列表中,它没有被字符串化,也没有参与粘贴。
由于 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
...还有事情 "work" 很好:
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,可能需要一些技巧才能实现它,但对于这个答案,我只专注于让你度过这个难关。
可以找到一个 PP_ARG_N()
实现,它也可以区分带参数和不带参数的调用 here (kudos to Scott Morrison)。对你的小程序的回应:
TEST PP_NARG: 0
TEST PP_NARG: 1
TEST PP_NARG: 2
TEST PP_NARG: 3