如何定义递归可变参数宏?

时间:2016-04-28 21:41:54

标签: c++ c visual-studio-2012 macros 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__部分没有正确扩展递归。这是真的吗?如果是,是否有解决方法?

1 个答案:

答案 0 :(得分:1)

显然,MS VC ++的行为与预期不同,__VA_ARGS__的递归扩展包括多个以逗号分隔的参数。在嵌套宏中展开时,编译器将整个arg列表视为一个参数。

还可以看到示例herehere

但是,@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__)))
// ...

现在消除了构建错误。

注意:我没有明确说“一个bug”,b / c可能有一个理解标准MS方式的地方,如here所述。