2016-04-28 13 views
0

Ich versuche, boolesche Werte, die Bits eines Signalbusses darstellen, in eine ganze Zahl zu konvertieren. Ich verwende das folgende Konstrukt:Wie definiere ich rekursive variadische Makros?

#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__)) 
// ... 

Wenn die Makrokaskade einen 1-, 2- und 3-Bit-Busse zu konvertieren, die ersten 2 sind in Ordnung, aber die 3-Bit-Umwandlung gibt einen Fehler:

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-Fehler auf line_3:

warning C4003: not enough actual parameters for macro 'B_TO_UINT1'

error C2059: syntax error : '<<'

So sieht der Teil __VA_ARGS__ nicht korrekt mit der Rekursion erweitert. Ist das wirklich der Fall? Wenn ja, gibt es einen Workaround?

+1

Nehmen Sie 'bxx' Dinge in Klammern. –

+0

@EugeneSh. - Vielen Dank. Im Allgemeinen ein guter Tipp, aber es löst dieses spezielle Problem nicht (ich bekomme andere, ')' verbundene Fehlermeldung). Jedenfalls kann ich im eigentlichen Code keine Klammern aus anderen Gründen verwenden. – ysap

+0

"* .. Jedenfalls kann ich im eigentlichen Code keine Klammern aus anderen Gründen verwenden. *" In diesem Fall hat der Code ein Problem. Wie auch immer, welche Nachricht bekommst du? –

Antwort

1

Anscheinend verhält sich MS VC++ anders als erwartet mit der rekursiven Erweiterung __VA_ARGS__, die mehrere durch Kommas getrennte Argumente enthält. Wenn der Compiler in einem verschachtelten Makro expandiert wird, behandelt er die gesamte Argumentliste als ein Argument.

Beispiele können auch here und here gesehen werden.

@Ise Wisteria schlug jedoch das EXPAND(x) Makro als Workaround vor. Mit diesem Tipp änderte ich meinen Code in:

#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__))) 
// ... 

Jetzt sind die Build-Fehler beseitigt.

Hinweis: Ich sage nicht explizit "ein Fehler", b/c gibt es einen Platz für das Verständnis des Standards der MS Weg, wie beschrieben here.