2016-07-15 154 views
6

ho una macro per ripetere le macro che uso per riempire gli array con i valori di default in fase di compilazione:C macro espansione ordine

const int array [512] = 
{ 
    MACRO_REPEAT(512, -2) // this repeats -2, 512 times 
    [4] = 10, 
    [5] = 2, 
    ... 
} 

La ripetizione macro si espanderà a MACRO_REPEAT_512, ma ora ho voluto usare altre macro come la dimensione della matrice, come:

#define ARRAY_LENGTH 512 
const int array [ARRAY_LENGTH ] = 
{ 
    MACRO_REPEAT(ARRAY_LENGTH , -2) // this repeats -2, 512 times 
    [4] = 10, 
    [5] = 2, 
    ... 
} 

Ma questo si espande per MACRO_REPEAT_ARRAY_LENGTH, non si espande ARRAY_LENGTH valore prima concatenazione esso. Altro esempio sarebbe per array multidimensionali, che coinvolge più livelli di espansione:

#define X 512 
#define Y 512 

const int array [X][Y] = 
{ 
    MACRO_REPEAT(X*Y , -2) // this repeats -2, 512 times 
    [4] = 10, 
    [5] = 2, 
    ... 
} 

Questo si espanderà per MARO_REPEAT_X * Y. Quindi, c'è un modo per espandere quei valori al valore numerico finale prima di concatenarlo ad altre macro?

+0

Perché non usare semplicemente un ciclo o 'memset()'? Sì, quelli lavorano in fase di esecuzione, ma ottengono l'effetto desiderato relativamente facilmente. – Peter

+2

GCC ha un'estensione che consente di inizializzare un intervallo di elementi con lo stesso valore, qualcosa come 'int array [ARRAY_LENGTH] = {[0 ... 3] = -2, [4] = 10, [5] = 2, [6 ... ARRAY_LENGTH - 1] = -2,}; ' –

+1

@Peter Lo so, ma sto lavorando in un sistema embedded e vorrei memorizzarlo in flash (domanda aggiornata con qualificatore const) – rnunes

risposta

1

È possibile risolvere il caso MACRO_REPEAT(ARRAY_LENGTH , -2) modificando la definizione di MACRO_REPEAT per utilizzare l'espansione a 2 fasi, vale a dire non utilizzare il token che incolla nello stesso MACRO_REPEAT, richiamare un'altra macro.

Non che ciò funzioni come previsto se ARRAY_LENGTH è definito come un token a numero singolo e se esiste una definizione di macro per questa dimensione specifica.

Non è possibile gestire il caso più generale MACRO_REPEAT(X*Y , -2) con il preprocessore C standard.

È possibile utilizzare l'estensione gcc per inizializzare gli array semplici:

#define MACRO_REPEAT(n, e) [ 0 ... (n)-1 ] = (e), 

Ma questo metodo non può essere utilizzato per gestire gli array multidimensionali come ad esempio MACRO_REPEAT(X*Y , -2).

Si potrebbe provare questo:

#define MACRO_REPEAT(n, e) [ 0 ... (n)-1 ] = (e), 
#define X 512 
#define Y 512 

const int array[X][Y] = { MACRO_REPEAT(X, { MACRO_REPEAT(Y, -2) }) }; 

Ma l'uso del preprocessore C solo offusca l'intento. Se decidi di affidarti alle estensioni di gcc, usale direttamente.

+0

Lo so, ma un array multidimensionale con colonne X e righe Y è solo un altro modo di guardare un array X * Y a dimensione singola. Credo che tu possa fare cose come int array [1] [2] = {first, second} e il primo sarà archiviato in [0] [0] e l'altro in [0] [1] – rnunes

+0

@munes: hai ragione : se è possibile espandere la macro in una sequenza di inizializzatori 262144, funzionerà. Prova 'MACRO_REPEAT (512, {MACRO_REPEAT (512, -2)})' con la tua definizione corrente della macro. – chqrlie

+0

@chqrlie non compila https://ideone.com/1GQf9N – 4pie0

1

Non sono sicuro che ciò contenga la risposta "giusta" in quanto non risponde direttamente alla domanda dell'OP, ma è una soluzione alternativa suggerita per il problema. Inoltre non è C standard poiché utilizza un'estensione GCC.

Nel compilatore GNU C (gcc), un intervallo di elementi di matrice può essere inizializzato allo stesso valore utilizzando il modulo [FIRST ... LAST] = VALUE. Risulta anche per permettere più inizializzatore designato per un elemento, per cui è possibile inizializzare una serie di elementi sullo stesso valore e quindi inizializzare elementi contenuti all'interno di tale intervallo di valori diversi, qualcosa di simile:

#define ARRAY_LENGTH 512 
const int array[ARRAY_LENGTH] = 
{ 
    [0 ... ARRAY_LENGTH - 1] = -2, 
    [4] = 10, 
    [5] = 2, 
    /* ... */ 
}; 
+0

sai cosa, hai ragione su questo non essendo la risposta alla domanda originale (quindi avrei reso più ampio). scusa per la richiesta di ripubblicazione, chqrlie risponde che è più vicino alla risposta giusta – rnunes