2012-06-14 37 views
10

Dado## preprocesador en C

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

La llamada cat(a,1) vuelve a1, pero cat(cat(1,2),3) no está definido. Sin embargo, si también defino #define xcat(x,y) cat(x,y), entonces el resultado de xcat(xcat(1,2),3) ahora es 123. ¿Puede alguien por favor explique en detalle por qué esto es así?

+0

¿Quiere decir 'entonces el resultado de xcat (xcat (1,2), 3) es ahora 123'? –

+0

@notfed: Lo siento, cometí un error al escribir la pregunta. Sí, el resultado de xcat (xcat (1,2), 3) es 123 – sourabh912

Respuesta

2

He probado esto usando tanto GCC como Clang.

GCC da el error:

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

Clang da el error:

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

Lo que parece estar sucediendo es que el compilador justifica el resultado de cat(1,2) paréntesis tan pronto como se expande ; así que cuando llamas al cat(1,2) en tu código, realmente te da (12). Luego, llamando al cat((12),3) nuevamente lleva a ((12)3), que no es un token válido, y esto da como resultado un error de compilación.

La opinión común es "cuando se utiliza el operador de pegar fichas (##), debe usar dos niveles de direccionamiento indirecto" (es decir, use su solución xcat). Ver Why do I need double layer of indirection for macros? y What should be done with macros that need to paste two tokens together?.

+0

En mi pregunta después de sustituir xcat (x, y) con cat (x, y) de nuevo se convierte en cat (cat (1,2), 3), incluso ahora debe devolver el token no válido. No puedo entender cómo funcionan los dos niveles de indirección. Leí la URL anterior, pero todavía no está muy claro para mí. – sourabh912

0

No creo que el gato se expanda en 2 ocasiones consecutivas. Es por eso que me pregunto por qué el compilador incluso produce un mensaje como 'pasting ")" and "3" does not give a valid preprocessing token'. Además, no creo que el gato interno vaya a expandirse primero. Por lo tanto, supongo que la salida sería cat(1,2)3. Eso me dirige a reflexionar sobre cómo interpretaría esto el compilador.

1

En xcat (x, y), las xey no están adyacentes al operador ##, y por lo que se someten a una expansión macro antes de ser sustituidas.

Así que x se identifica como xcat (1,2) e y se identifica como 3. Pero antes para la sustitución, x se expande macro a cat (1,2), que se convierte en 1 ## 2 que se convierte en 12. por lo tanto, en última instancia, xcat (xcat (1,2), 3) se expandirá al gato (12,3), que va a salir 123.

Esto funciona -> gato (xcat (1 , 2), 3) -> cat (cat (1,2), 3) -> cat (12,3)

El comportamiento está bien definido porque todos los tokens resultan válidos tokens de preprocesador es decir, cualquier xpression expandido debe ser un token válido en cualquier etapa.

+0

Bueno, su ejemplo no funcionó, pero 'xcat (cat (1,2), 3)' lo hizo de todos modos. – Niloct