2011-01-27 28 views
12

Immagino che la maggior parte di voi che ha lavorato con C/C++ abbia intuito come funziona il preprocessore (più o meno). L'ho pensato fino ad oggi, ma la mia intuizione è stata smentita. Ecco la storia:(Strambo?) Comportamento del preprocessore GCC

Oggi ho provato qualcosa, ma non riesco a spiegare il risultato. in primo luogo considerare il seguente codice:

#define A B 
#define B A 

A 
B 

Che cosa succede? Ebbene, il risultato dopo la compilazione con il flag -E 'questa:

A 
B 

Beh, ok, forse non quello che chiunque si aspetterebbe, ma è spiegabile. Immagino che il preprocessore abbia in qualche modo capito che c'è qualche problema, e non l'ha fatto.

La prossima cosa che ho provato è stato questo:

#define A B 
#define B A C 
#define C x 

A 
B 

Ora per la, per me, risultato inspiegabile:

A x 
B x 

come è potuto succedere? Non riesco a capire un modo ragionevole di come sia successo. Il primo comando (#define A B) non può essere eseguito, in quanto A sarebbe sostituito da B e il risultato finale dovrebbe essere uguale per entrambi. Ma se non lo è, allora non è possibile che "A x" possa accadere!

La mia domanda: cosa mi manca? Ovviamente non conosco il modo esatto di come funziona il preprocessore. Conosci qualche fonte al riguardo?

+0

E questo è il motivo per cui #defines ha bisogno di evitare ... – Goz

+0

Sì, questo è un altro motivo .. Non intendo dire di non usarli affatto. Per alcuni compiti sono molto utili (e la via da percorrere io.m.o.). – George

risposta

13

Self-Referential Macros spiega. L'espansione viene applicata in profondità ma si interrompe una volta che una macro fa riferimento a se stessa.

+0

Collegamento piacevole e utile, grazie! – George

5
#define A B 
#define B A C 
#define C x 

A -> B -> A C -> A x 
B -> A C -> B x 

L'espansione è token Token "pigramente"

3

Beh, ok, forse non quello che chiunque si aspetterebbe , ma è spiegabile. Immagino che sia il che il preprocessore in qualche modo ha capito che c'è qualche problema e che non ha funzionato.

No. Se il preprocessore esegue un'espansione, espande un simbolo solo una volta. Quindi nel tuo primo esempio per A: A gets è espanso in B, B si espande in A e qui l'espansione si ferma. Nella seconda riga la B viene espansa in una A che si espande in una B, dove l'espansione si ferma, perché abbiamo già espanso B.

Se si applica la logica al secondo esempio, il risultato diventa immediatamente evidente.

5

Ogni catena di sostituzioni può visitare una definizione di macro al massimo una volta. Tra le altre cose, questo significa che non puoi avere macro ricorsive.

Le sostituzioni per il tuo secondo esempio sarà simile a questo:

A --[evaluate A]--> B --[evaluate B]--> A C --[evaluate C]--> A x 
B --[evaluate B]--> A C --[evaluate A,C]--> B x 

Durante l'ultima fase della prima linea, A non viene valutata perché è stato già richiamato in precedenza. Allo stesso modo, nella seconda riga, la valutazione si ferma a B perché è già stata visitata durante il primo passaggio.

La sezione pertinente dello standard C99 sarebbe 6.10.3.4 Rescansione e ulteriore sostituzione.

+0

Grazie per la spiegazione! Stavo pensando nel contesto di Grammars and Languages ​​e ho totalmente perso quella spiegazione ovvia. – George

Problemi correlati