如何定义递归可变参数宏?
How to define recursive variadic macros?
我正在尝试将表示信号总线位的布尔值转换为整数。我正在使用以下构造:
#define B_TO_UINT1(b00) (((uint32_t) b00 << 0))
#define B_TO_UINT2(b01, ...) (((uint32_t) b01 << 1) | B_TO_UINT1(__VA_ARGS__))
#define B_TO_UINT3(b02, ...) (((uint32_t) b02 << 2) | B_TO_UINT2(__VA_ARGS__))
#define B_TO_UINT4(b03, ...) (((uint32_t) b03 << 3) | B_TO_UINT3(__VA_ARGS__))
// ...
使用宏级联转换1、2、3位总线时,前2位没问题,但3位转换报错:
cmd = B_TO_UINT1(1); // line_1
cmd = B_TO_UINT2(1, 0); // line_2
cmd = B_TO_UINT3(0, 1, 1); // line_3
line_3
上的构建错误:
warning C4003: not enough actual parameters for macro 'B_TO_UINT1'
error C2059: syntax error : '<<'
所以,看起来 __VA_ARGS__
部分没有通过递归正确扩展。真的是这样吗?如果是这样,是否有解决方法?
显然,MS VC++ 的行为与预期的不同,因为 __VA_ARGS__
的递归扩展包含多个逗号分隔的参数。在嵌套宏中扩展时,编译器将整个 arg 列表视为一个参数。
例子也可以看here and here.
但是,@Ise Wisteria 建议使用 EXPAND(x)
宏作为解决方法。使用此技巧,我将代码更改为:
#define EXPAND( x ) x
#define B_TO_UINT1(b00) (((uint32_t) b00 << 0))
#define B_TO_UINT2(b01, ...) (((uint32_t) b01 << 1) | EXPAND( B_TO_UINT1(__VA_ARGS__)))
#define B_TO_UINT3(b02, ...) (((uint32_t) b02 << 2) | EXPAND( B_TO_UINT2(__VA_ARGS__)))
#define B_TO_UINT4(b03, ...) (((uint32_t) b03 << 3) | EXPAND( B_TO_UINT3(__VA_ARGS__)))
// ...
现在消除了构建错误。
注意:我没有明确说 "a bug",b/c 可能有一个地方可以理解标准的 MS 方式,如 here 所述。
我正在尝试将表示信号总线位的布尔值转换为整数。我正在使用以下构造:
#define B_TO_UINT1(b00) (((uint32_t) b00 << 0))
#define B_TO_UINT2(b01, ...) (((uint32_t) b01 << 1) | B_TO_UINT1(__VA_ARGS__))
#define B_TO_UINT3(b02, ...) (((uint32_t) b02 << 2) | B_TO_UINT2(__VA_ARGS__))
#define B_TO_UINT4(b03, ...) (((uint32_t) b03 << 3) | B_TO_UINT3(__VA_ARGS__))
// ...
使用宏级联转换1、2、3位总线时,前2位没问题,但3位转换报错:
cmd = B_TO_UINT1(1); // line_1
cmd = B_TO_UINT2(1, 0); // line_2
cmd = B_TO_UINT3(0, 1, 1); // line_3
line_3
上的构建错误:
warning C4003: not enough actual parameters for macro 'B_TO_UINT1'
error C2059: syntax error : '<<'
所以,看起来 __VA_ARGS__
部分没有通过递归正确扩展。真的是这样吗?如果是这样,是否有解决方法?
显然,MS VC++ 的行为与预期的不同,因为 __VA_ARGS__
的递归扩展包含多个逗号分隔的参数。在嵌套宏中扩展时,编译器将整个 arg 列表视为一个参数。
例子也可以看here and here.
但是,@Ise Wisteria 建议使用 EXPAND(x)
宏作为解决方法。使用此技巧,我将代码更改为:
#define EXPAND( x ) x
#define B_TO_UINT1(b00) (((uint32_t) b00 << 0))
#define B_TO_UINT2(b01, ...) (((uint32_t) b01 << 1) | EXPAND( B_TO_UINT1(__VA_ARGS__)))
#define B_TO_UINT3(b02, ...) (((uint32_t) b02 << 2) | EXPAND( B_TO_UINT2(__VA_ARGS__)))
#define B_TO_UINT4(b03, ...) (((uint32_t) b03 << 3) | EXPAND( B_TO_UINT3(__VA_ARGS__)))
// ...
现在消除了构建错误。
注意:我没有明确说 "a bug",b/c 可能有一个地方可以理解标准的 MS 方式,如 here 所述。