2012-06-14 24 views
10

DatoCirca ## preprocessore in C

#define cat(x,y) x##y 

La chiamata cat(a,1) rendimenti a1, ma cat(cat(1,2),3) è indefinito. Tuttavia, se definisco anche #define xcat(x,y) cat(x,y), il risultato di xcat(xcat(1,2),3) è ora 123. Qualcuno può spiegare in dettaglio perché è così?

+0

Vuoi dire 'allora il risultato di xcat (xcat (1,2), 3) è ora 123'? –

+0

@notfed: Scusa ho commesso un errore nello scrivere la domanda. Sì il risultato di xcat (xcat (1,2), 3) è 123 – sourabh912

risposta

2

Ho provato questo utilizzando sia GCC e Clang.

GCC dà l'errore:

test.c:6:1: error: pasting ")" and "3" does not give a valid preprocessing token 

Clang dà l'errore:

test.c:6:11: error: pasting formed ')3', an invalid preprocessing token 
    int b = cat(cat(1,2),3); 

Quello che sembra accadere è che il compilatore avvolge il risultato di cat(1,2) tra parentesi non appena si espande ; quindi quando chiami cat(1,2) nel tuo codice, ti dà davvero (12). Quindi, chiamando cat((12),3) di nuovo conduce a ((12)3), che non è un token valido e questo si traduce in un errore di compilazione.

L'opinione comune è "quando si utilizza l'operatore di token-pasting (##), è necessario utilizzare due livelli di riferimento indiretto" (ad esempio, utilizzare la soluzione alternativa xcat). Vedi Why do I need double layer of indirection for macros? e What should be done with macros that need to paste two tokens together?.

+0

Nella mia domanda dopo aver sostituito xcat (x, y) con cat (x, y) diventa nuovamente cat (cat (1,2), 3) quindi anche ora dovrebbe restituire un token non valido. Non riesco a capire come funzionino i due livelli di riferimento indiretto. Ho letto l'URL sopra, ma ancora non mi è chiaro. – sourabh912

0

Non penso che il gatto verrà effettivamente espanso per 2 volte consecutive. Ecco perché mi chiedo perché il compilatore potrebbe anche produrre un messaggio come 'pasting ")" and "3" does not give a valid preprocessing token'. Inoltre, non credo che il gatto interiore verrà prima espanso. Quindi, presumo che l'output sarebbe cat(1,2)3. Questo mi ha indotto a cogitare come interpreterebbe il compilatore.

1

In xcat (x, y), xey non sono adiacenti all'operatore ## e quindi subiscono l'espansione macro prima di essere sostituiti.

Quindi x è identificato come xcat (1,2) e y è identificato come 3. Ma prima di sostituzione, x è macro-espanso a cat (1,2), che si trasforma in 1 ## 2 cui si trasforma in 12. Quindi in ultima analisi, xcat (xcat (1,2), 3) si espanderà al gatto (12,3), che si rivelerà 123.

Questo funziona -> cat (xcat (1 , 2), 3) -> cat (cat (1,2), 3) -> cat (12,3)

Il comportamento è ben definito perché tutti gli invii di token risultano validi i token del preprocessore vale a dire qualsiasi xpression espansa dovrebbe essere un gettone valido in qualsiasi momento.

+0

Bene, il tuo esempio non ha funzionato, ma 'xcat (cat (1,2), 3)' ha fatto comunque. – Niloct