2011-10-17 15 views
9

Vorrei valutare un token prima che sia concatenato con qualcos'altro. Il "problema" è che lo standard specifica il comportamento comeValuta il token del preprocessore prima della ## concatenazione

prima che la lista di sostituzione è riesaminata per i nomi più macro per sostituire, ogni istanza di un gettone ## pre-elaborazione della lista di sostituzione (non da un argomento) viene eliminato e il token di preelaborazione precedente viene concatenato con il seguente token di preelaborazione.

quindi nel seguente esempio,

#include <stdlib.h> 

struct xy { 
    int x; 
    int y; 
}; 

struct something { 
    char * s; 
    void *ptr; 
    int size; 
    struct xy *xys; 
}; 
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) 

#define DECLARE_XY_BEGIN(prefix) \ 
struct xy prefix ## _xy_table[] = { 

#define XY(x, y) {x, y}, 

#define DECLARE_XY_END(prefix) \ 
    {0, 0} \ 
}; \ 
struct something prefix ## _something = { \ 
    "", NULL, \ 
    ARRAY_SIZE(prefix ## _xy_table), \ 
    &(prefix ## _xy_table)[0], \ 
}; 

DECLARE_XY_BEGIN(linear1) 
    XY(0, 0) 
    XY(1, 1) 
    XY(2, 2) 
    XY(3, 3) 
DECLARE_XY_END(linear1) 


#define DECLARE_XY_BEGIN_V2() \ 
struct xy MYPREFIX ## _xy_table[] = { 

#define DECLARE_XY_END_V2() \ 
    {0, 0} \ 
}; \ 
struct something MYPREFIX ## _something = { \ 
    "", NULL, \ 
    ARRAY_SIZE(MYPREFIX ## _xy_table), \ 
    &(MYPREFIX ## _xy_table)[0], \ 
}; 

#define MYPREFIX linear2 
DECLARE_XY_BEGIN_V2() 
    XY(0, 0) 
    XY(2, 1) 
    XY(4, 2) 
    XY(6, 3) 
DECLARE_XY_END_V2() 
#undef MYPREFIX 

L'ultima dichiarazione si espande in

struct xy MYPREFIX_xy_table[] = { 
{0, 0}, 
{2, 1}, 
{4, 2}, 
{6, 3}, 
{0, 0} }; struct something MYPREFIX_something = { "", 0, (sizeof(MYPREFIX_xy_table)/sizeof((MYPREFIX_xy_table)[0])), &(MYPREFIX_xy_table)[0], }; 

e non

struct xy linear2_xy_table[] = { 
{0, 0}, 
{2, 1}, 
{4, 2}, 
{6, 3}, 
{0, 0} }; struct something linear2_something = { "", 0, (sizeof(linear2_xy_table)/sizeof((linear2_xy_table)[0])), &(linear2_xy_table)[0], }; 

come voglio. C'è un modo per definire le macro che producono questo? La prima serie di macro lo fa, ma vorrei evitare la duplicazione del prefisso e avere questa definizione solo una volta. Quindi è possibile impostare il prefisso con #define e lasciare che le macro lo usino?

+0

possibile duplicato di [Come concatenare due volte con il preprocessore C ed espandere una macro come in "arg ## \ _ # # MACRO "?] (Http://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocess-and-expand-a-macro-as-in-arg) Per favore prova per minimizzare esempi :-) –

risposta

4

È possibile utilizzare l'espansione di secondo livello per questo, ad es.

#define XY_HLP1(a) DECLARE_XY_BEGIN(a) 
#define XY_HLP2(a) DECLARE_XY_END(a) 
#define DECLARE_XY_BEGIN_V2() XY_HLP1(MYPREFIX) 
#define DECLARE_XY_END_V2() XY_HLP2(MYPREFIX) 
+0

Sì, mi piace. Non c'è bisogno di cambiare i vecchi macro e creare possibili problemi di unione per gli altri, e anche se la doppia espansione potrebbe non essere intuitivamente comprensibile, è comunque ovvio che lo stesso prefisso sia utilizzato in entrambe le posizioni. – hlovdal

11

You can use a macro for concatenation come

#define CONCAT_(A, B) A ## B 
#define CONCAT(A, B) CONCAT_(A, B) 

questo funziona allora

#define A One 
#define B Two 
CONCAT(A, B) // Results in: OneTwo 
+1

Non ho mai capito perché queste cose richiedono due livelli. Il primo livello per l'espansione macro e il secondo per l'effettiva concatenazione? – ijustlovemath