2015-09-25 11 views
5

Ich versuche, die Deklaration eines Arrays zu vereinfachen, stieß aber auf ein Problem mit den Präprozessoren, die ich verwende. Mein anfänglicher Code sieht wie folgt aus:Preprocessor schlägt fehl - '#' wird nicht von einem Makroparameter gefolgt

#define REQ_ENTRY(parm_1, parm_2) \ 
#if defined(parm_1)     \ 
    { parm_1, parm_2 },    \ 
#endif 

typedef struct { 
    int parm1, 
     parm2; 
} MyTypedef_t; 

static const MyTypedef_t MyList[] = 
{ 
    REQ_ENTRY(ID_1, 1) 
    REQ_ENTRY(ID_2, 2) 
    REQ_ENTRY(ID_3, 3) 
    REQ_ENTRY(ID_4, 4) 
    REQ_ENTRY(ID_5, 5) 
}; 

Der Build fehlschlägt, natürlich mit der Fehlermeldung „Fehler:‚#‘wird nicht von einem Makroparameter gefolgt“. Der Grund dafür wird hier erklärt (Why compiler complain about this macro declaration)

Grundsätzlich ich das Array zu vermeiden versuchen zu erklären, wie die folgt, was funktioniert:

static const MyTypedef_t MyList[] = 
{ 
    #if defined (ID_1) 
    { ID_1, 1 }, 
    #endif 

    #if defined (ID_2) 
    { ID_2, 2 }, 
    #endif 

    #if defined (ID_3) 
    { ID_3, 3 }, 
    #endif 

    #if defined (ID_4) 
    { ID_4, 4 }, 
    #endif 

    #if defined (ID_5) 
    { ID_5, 5 }, 
    #endif   
}; 

Die Liste kann ziemlich lang sein und variiert in Abhängigkeit von der Build-Typ des Projekts. Ich habe versucht, X-Makros zu verwenden, aber ich denke, ich hätte das gleiche Problem. Ich hoffe, dass jemand eine Möglichkeit sieht, die Präprozessor-Makros so zu erstellen, dass ich die ursprüngliche Zuckersyntax erreichen kann? Jede Einsicht wird sehr geschätzt.

+6

Sie können '# ifdef 'um eine Makrodefinition wickeln; Sie können es nicht in einem einbetten. Außerdem können Sie nicht direkt testen, ob ein Argument für ein Makro ein definiertes Makro ist.Leider ist das Neinsagen der einfache Teil; Es ist nicht klar, dass es einen guten Weg gibt, den ursprünglichen Code zu vermeiden. Das habe ich unter ähnlichen Umständen benutzt. –

Antwort

3

Es gibt keine schöne saubere Lösung. Aber es gibt Lösungen von unterschiedlicher Hässlichkeit.

Wenn Sie nicht mit nichts dagegen sowohl die id und der Sequenz in der Makrodefinition kann es wie folgt gelöst werden:

#define CONCAT2(x,y) x##y 
#define CONCAT(x,y) CONCAT2(x,y) 
#define REQ_ENTRY_YES(p1, p2) { p1 , p2 } 
#define REQ_ENTRY_NO(p1) 
#define IS_PAIR_HELPER(a, b, c, ...) c 
#define IS_PAIR(...) IS_PAIR_HELPER(__VA_ARGS__, YES, NO) 
#define REQ_ENTRY(pair) CONCAT(REQ_ENTRY_, IS_PAIR(pair))(pair) 

#define ID_1 78723649, 1 
#define ID_3 2347602, 3 

typedef struct { 
    int parm1, 
     parm2; 
} MyTypedef_t; 

static const MyTypedef_t MyList[] = 
{ 
    REQ_ENTRY(ID_1) 
    REQ_ENTRY(ID_2) 
    REQ_ENTRY(ID_3) 
    REQ_ENTRY(ID_4) 
    REQ_ENTRY(ID_5) 
}; 

Run durch gcc mit -std=c11 -Wall -E und zeigt nur die MyList Definition:

static const MyTypedef_t MyList[] = 
{ 
    { 78723649 , 1 } 

    { 2347602 , 3 } 


}; 

Sie können dasselbe tun, indem Sie einen beliebigen zweiten Wert in den #define ID_x Makros verwenden, solange es einen gibt; Die realen Parameter können zu REQ_ENTRY hinzugefügt werden. Aber es braucht ein bisschen mehr Jonglieren.

1

Es ist schade, dass der Operator defined nur im Kontext von #if und #ifelse verfügbar ist, aber nicht für Makroerweiterungen. So wie es aussieht, stimme ich Rici zu den Lösungen unterschiedlicher Hässlichkeit zu.

Hier ist eine Lösung, die erfordert, dass die definierten Werte in Klammern eingeschlossen sind. Sie können dann die ID als regulären Wert verwenden und sie auch an DEF übergeben, die entweder auf 1 erweitert wird, wenn das Makro in Klammern steht, oder auf 0, wenn dies nicht der Fall ist. (Das ist ein Trick, den ich here gelernt.)

Mit Hilfe des DEF Makro, können Sie Hilfs Makros erstellen, die die gegebene Definition erweitern oder ignorieren:

/* Auxiliary macros */ 

#define M_CHECK(...) M_CHECK_(__VA_ARGS__) 
#define M_CHECK_(a, b, ...) b 

#define M_IS_PAREN(x) M_CHECK(M_IS_PAREN_ x, 0) 
#define M_IS_PAREN_(...) 1, 1 

#define M_CONCAT(a, b) M_CONCAT_(a, b) 
#define M_CONCAT_(a, b) a ## b 

/* Conditional definition macros */ 

#define DEF(x) M_IS_PAREN(x) 

#define DEF_IF_0(id, def) 
#define DEF_IF_1(id, def) {id, def}, 

#define COND_DEF(x, y) M_CONCAT(DEF_IF_, DEF(x))(x, y) 

/* Implementation */ 

#define ID_1 (27) 
#define ID_3 (28) 
#define ID_4 (29) 

static const MyTypedef_t MyList[] = { 
    COND_DEF(ID_1, 1) 
    COND_DEF(ID_2, 2) 
    COND_DEF(ID_3, 3) 
    COND_DEF(ID_4, 4) 
    COND_DEF(ID_5, 5) 
}; 

Dies erzeugt:

static const MyTypedef_t MyList[] = { 
    {(27), 1}, 

    {(28), 3}, 
    {(29), 4}, 

}; 

Sie können auch die DEF Makro im Code verwenden, die entweder auf 0 erweitert werden oder 1:

printf("ID_1 is %s.\n", DEF(ID_1) ? "defined" : "undefined"); 
Verwandte Themen