2015-09-25 15 views
5

Próbuję uprościć deklarację tablicy, ale wystąpił problem z preprocesorami, których używam. Mój początkowy kod wygląda tak:Preprocesor przestaje działać z powodu - po '#' nie następuje parametr makro

#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) 
}; 

Kompilacja nie powiedzie się, oczywiście, z komunikatem o błędzie „Błąd:«#»nie następuje makro parametru”. Powodem tego jest wyjaśnione tutaj (Why compiler complain about this macro declaration)

Zasadniczo, staram się unikać deklarowania tablicy jak poniżej, które działa:

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   
}; 

Lista może być dość długi i różnią się w zależności od typ budowy projektu. Próbowałem myśleć o używaniu x-makr, ale myślę, że miałbym ten sam problem. Mam nadzieję, że ktoś może zobaczyć sposób tworzenia makr preprocesora w taki sposób, żebym mógł osiągnąć oryginalną składnię cukru? Każdy wgląd jest bardzo doceniany.

+6

Możesz zawijać '# ifdef' wokół definicji makra; nie możesz go osadzić w jednym. Ponadto nie można bezpośrednio sprawdzić, czy argument do makra jest zdefiniowanym makrem.Niestety, naiwne powiedzenie jest łatwą częścią; nie jest jasne, czy istnieje dobry sposób na uniknięcie oryginalnego kodu. Właśnie tego użyłem w podobnych okolicznościach. –

Odpowiedz

3

Nie ma ładnego, czystego rozwiązania. Ale są rozwiązania o różnej brzydocie.

Jeśli nie przeszkadza w tym zarówno id i sekwencją w definicji makra , może być rozwiązany w ten sposób:

#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 przez gcc z -std=c11 -Wall -E i pokazując tylko definicja MyList:

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

    { 2347602 , 3 } 


}; 

Możesz zrobić to samo, używając dowolnej drugiej wartości w makrach #define ID_x, o ile istnieje; prawdziwe parametry można dodać do REQ_ENTRY. Ale wymaga to dodatkowej żonglerki.

1

Szkoda, że ​​operator defined jest dostępny tylko w kontekście #if i #ifelse, ale nie w przypadku rozszerzeń makro. W obecnej formie zgadzam się z rici na temat rozwiązań o różnej brzydocie.

Oto rozwiązanie, które wymaga, aby zdefiniowane wartości były otoczone nawiasami. Następnie możesz użyć identyfikatora jako wartości regularnej i możesz go również przekazać do DEF, która rozwija się do 1, gdy makro znajduje się w nawiasie lub 0, jeśli nie. (To sztuczka dowiedziałem here.)

Z pomocą DEF makra można tworzyć makra pomocnicze, które rozszerzają lub zignorować daną definicję:

/* 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) 
}; 

To będzie produkować:

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

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

}; 

Można również użyć kodu DEF w kodzie, który zostanie rozszerzony do 0 lub 1:

printf("ID_1 is %s.\n", DEF(ID_1) ? "defined" : "undefined"); 
Powiązane problemy