2009-08-17 38 views
5

E 'possibile definire una macro C/C++ "BUILD(a, i)" che si espande in "x[0], x[1], x[2], ..., x[i]"? Come inEspansione ricorsiva macro in sequenza

#define BUILD(x, 0) x[0] 
#define BUILD(x, 1) x[0], x[1] 
#define BUILD(x, 2) x[0], x[1], x[2] 
... 

Sembra che BOOST_PP_ENUM_PARAMS potrebbe fare il lavoro. Suppongo che potrei solo includere la spinta, ma sono interessato a sapere come e perché funziona, qualcuno può spiegare?

desidero chiamare una funzione che prende f(int, ...) N int argomenti x[i], 0 < = i < N. Se N è noto per essere ceil(sizeof(A)/sizeof(B)). Quindi, sfortunatamente, non posso usare vararg o template.

+0

correlato: http://stackoverflow.com/questions/824639/variadic-recursive-preprocessor-macros-is-it-possible/893684 –

+0

Quale problema stai veramente cercando di risolvere? vale a dire. per cosa sarà usato il risultato di questa macro? L'utilizzo potrebbe essere leggermente modificato per consentire una soluzione di template (dove è possibile la ricorsione)? –

+0

Vedere la mia ultima modifica. –

risposta

14

È possibile, ma è necessario eseguire alcune operazioni manuali e avere un limite superiore.

#define BUILD0(x) x[0] 
#define BUILD1(x) BUILD0(x), x[1] 
#define BUILD2(x) BUILD1(x), x[2] 
#define BUILD3(x) BUILD2(x), x[3] 
#define BUILD(x, i) BUILD##i(x) 

e notare che i deve essere un numero intero letterale, non un valore calcolato costante.

BTW, il preprocessore è più potente di quello che è in genere, ma l'utilizzo di tale potenza è piuttosto complicato. Boost fornisce una libreria che facilita alcune cose, inclusa l'iterazione. Vedi Boost Preprocessor Library. C'è un'altra biblioteca per queste cose, ma il suo nome mi sfugge al momento.

Modifica: la libreria di preprocessore boost utilizza una tecnica simile. Con trucchi aggiuntivi per risolvere alcuni problemi di casi d'angolo, condividere macro di implementazione tra strutture di livello superiore, aggirare i bug del compilatore, ecc ... la solita complessità di boost che è normale nel contesto di una libreria generica ma che a volte impedisce una facile comprensione di i principi di attuazione. Probabilmente il trucco più evidente è quello di aggiungere un livello di riferimento indiretto in modo che se il secondo parametro può essere una macro, viene espanso. Cioè con

#define BUILD_(x, i) BUILD##i(x) 
#define BUILD(x, i) BUILD_(x, i) 

si può effettuare la chiamata

#define FOO 42 
BUILD(x, FOO) 

che non è possibile con quello che ho esposto.

+0

Grazie, è interessante come BUILD1..BUILD3 sono quasi identici ... non potrei avere qualcosa come #define BUILD_ (x, j) BUILD_ (x, j-1), x [j] –

+0

Non avrebbe una condizione di arresto e le macro non possono essere ricorsive all'avvio. – Blindy

+0

+1 per una bella spiegazione! –

2

No, non lo è: i macro non possono essere ricorsivi. E le macro che hai postato non sono variadiche, il che significa "avere un numero diverso di parametri".

+1

Grazie, ho rimosso il tag variadic. –

0

Ok, Ho avuto lo stesso problema, il mio obiettivo era quello di stampare tutti i valori di un array di N byte usando le macro. Presumo che tu abbia più o meno lo stesso problema. In questo caso, questa soluzione dovrebbe soddisfare futuri problemi simili.

#define HEX_ARRAY_AS_STR(array, len) \ 
    ({ \ 
     int print_counter = 0; \ 
     print_buf = calloc(len*3+1, 1); \ 
     char *tmp_print_buf = print_buf; \ 
     uint8_t *array_flower = array; \ 
     while(print_counter++ < (len)){ \ 
      sprintf(tmp_print_buf, "%02X ", *(array_flower)++); \ 
      tmp_print_buf += 3; \ 
     } \ 
     print_buf; \ 
    }) 

#define eprintf(...) \ 
    do{ \ 
     char *print_buf; \ 
     printf(__VA_ARGS__); \ 
     if(print_buf) \ 
      free(print_buf); \ 
    }while(0) 

int 
main(int argc, char *argv[]) 
{ 
    uint8_t sample[] = {0,1,2,3,4,5,6,7}; 
    eprintf("%s\n", HEX_ARRAY_AS_STR(sample, 8)); 
    return 0; 
} 
+0

No, non è quello che stavo cercando di fare. Ad ogni modo, se passi sempre un array a HEX_ARRAY_AS_STR, puoi eliminare il secondo parametro usando sizeof (array)/sizeof (uint8_t) –