2011-01-27 16 views
12

Supongo que la mayoría de los que han trabajado con C/C++ tienen una intuición de cómo funciona el preprocesador (más o menos). Eso creí hasta hoy, pero mi intuición fue errónea. Aquí está la historia:(¿Extraño?) Comportamiento del preprocesador GCC

Hoy intenté algo, pero no puedo explicar el resultado. en primer lugar considerar el siguiente código:

#define A B 
#define B A 

A 
B 

¿Qué ocurre? Así, el resultado después de compilar con la bandera -E es la siguiente:

A 
B 

Bueno, bueno, tal vez no lo que cualquiera esperaría, pero es explicable. Supongo que el preprocesador de alguna manera descubrió que hay algún problema, y ​​no lo entendía.

La siguiente cosa que probé fue la siguiente:

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

A 
B 

Ahora a la, para mí, resultado inexplicable:

A x 
B x 

¿Cómo sucedió esto? No puedo encontrar una forma razonable de cómo sucedió esto. El primer comando (#define A B) no se puede ejecutar, porque luego A sería reemplazado por B, y el resultado final debería ser el mismo para ambos. ¡Pero si no lo es, entonces no hay forma de que pueda suceder "A x"!

Mi pregunta: ¿Qué me estoy perdiendo? Obviamente no sé la forma exacta de cómo funciona el preprocesador. ¿Conoces alguna fuente al respecto?

+0

Y esta es la razón por #defines es necesario evitar ... – Goz

+0

Sí, esta es otra razón ... No es que quiera decir que no los use en absoluto. Para algunas tareas son muy útiles (y la forma de hacerlo es i.m.o.). – George

Respuesta

13

Self-Referential Macros explica. La expansión se aplica profundamente pero se detiene una vez que una macro se refiera a sí misma.

+0

Enlace agradable y útil, gracias! – George

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

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

La expansión es token token "perezosa"

3

Pues bien, tal vez no lo que cualquiera esperar, pero es explicable. Supongo que el preprocesador de alguna manera calculó que hay algún problema, y ​​ no lo hizo.

Nope. Si el preprocesador realiza una expansión, expande un símbolo solo una vez. Entonces, en su primer ejemplo para A: A gets's expandido a B, B se expande a A y aquí la expansión se detiene. En la segunda línea, B se expande a A, que se expande a B, donde la expansión se detiene, porque ya expandimos B.

Si aplica la lógica a su segundo ejemplo, el resultado se vuelve inmediatamente obvio.

5

Cada cadena de sustituciones puede visitar cualquier definición de macro como máximo una vez. Entre otras cosas, esto significa que no puede tener macros recursivas.

Las sustituciones para el segundo ejemplo se vería así:

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

Durante el último paso de la primera línea, A no se evalúa porque ya fue invocado previamente. De manera similar, en la segunda línea, la evaluación se detiene en B porque ya se ha visitado durante el primer paso.

La sección correspondiente del estándar C99 sería 6.10.3.4 Reescaneo y posterior reemplazo.

+0

¡Gracias por la explicación! Estaba pensando en el contexto de Grammars and Languages ​​y extrañé por completo esa explicación obvia. – George