Reputation: 8115
I am trying to convert boolean values, which represent bits of a signal bus, into an integer. I am using the following construct:
#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__))
// ...
When using the macro cascade to convert a 1-, 2- and 3-bit buses, the first 2 are OK, but the 3-bit conversion gives an error:
cmd = B_TO_UINT1(1); // line_1
cmd = B_TO_UINT2(1, 0); // line_2
cmd = B_TO_UINT3(0, 1, 1); // line_3
Build errors on line_3
:
warning C4003: not enough actual parameters for macro 'B_TO_UINT1'
error C2059: syntax error : '<<'
So, looks like the __VA_ARGS__
part is not expanding correctly with the recursion. Is this really the case? If so, is there a workaround?
Upvotes: 0
Views: 1451
Reputation: 8115
Apparently, MS VC++ behaves differently than expected with the recursive expansion of __VA_ARGS__
that includes multiple comma-separated arguments. When expanded in a nested macro, the the compiler treats the whole arg list as one argument.
Examples can also be seen here and here.
However, @Ise Wisteria suggested the EXPAND(x)
macro as a workaround. Using this tip, I changed my code to:
#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__)))
// ...
Now the build errors are eliminated.
Note: I am not explicitly saying "a bug", b/c there may be a place for understanding the standard the MS way, as described here.
Upvotes: 1