¿Por qué necesito doble capa de indirección para macros?

En: Preguntas frecuentes sobre C ++ – Problemas técnicos misceláneos – [39.6] ¿Qué se debe hacer con las macros que necesitan pegar dos fichas juntas?

¿Podría alguien explicarme por qué ? Todo lo que leo es, créanme , pero simplemente no puedo confiar en algo porque alguien lo dijo.

Probé el enfoque y no puedo encontrar ningún error que aparezca:

#define mymacro(a) int a ## __LINE__ mymacro(prefix) = 5; mymacro(__LINE__) = 5; int test = prefix__LINE__*__LINE____LINE__; // fine 

Entonces, ¿por qué tengo que hacerlo así? (Cita de la página web):

Sin embargo, necesita una doble capa de direccionamiento indirecto cuando usa ##. Básicamente, debe crear una macro especial para “pegar token”, como:

  #define NAME2(a,b) NAME2_HIDDEN(a,b) #define NAME2_HIDDEN(a,b) a ## b 

Confía en mí en esto, ¡realmente necesitas hacer esto! (Y por favor, nadie me escriba diciéndome que a veces funciona sin la segunda capa de indirección. Intente concatenar un símbolo con __ LINE__ y vea qué sucede entonces).

Editar: ¿Podría alguien también explicar por qué usa NAME2_HIDDEN antes de que se declare a continuación? Parece más lógico definir la macro NAME2_HIDDEN antes de usarla. ¿Es algún tipo de truco aquí?

La parte relevante de la especificación C:

6.10.3.1 Sustitución de argumento

Una vez identificados los argumentos para la invocación de una macro de tipo función, se produce la sustitución de los argumentos. Un parámetro en la lista de reemplazo, a menos que sea precedido por un token de preprocesamiento # o ## o seguido de un token de preprocesamiento ## (consulte a continuación), se reemplaza por el argumento correspondiente después de que se hayan expandido todas las macros contenidas en él. Antes de ser sustituidos, los tokens de preprocesamiento de cada argumento se reemplazan completamente macro como si formaran el rest del archivo de preprocesamiento; no hay otros tokens de preprocesamiento disponibles.

La parte clave que determina si desea la doble indirección o no es la segunda oración y la excepción; si el parámetro está involucrado en una operación # o ## (como params en mymacro y NAME2_HIDDEN ), entonces cualquier otro las macros en el argumento NO se expanden antes de hacer el # o ## . Si, por otro lado, no hay # o ## INMEDIATAMENTE en el cuerpo de la macro (como con NAME2 ), entonces se expanden otras macros en los parámetros.

Por lo tanto, todo se reduce a lo que desea: a veces desea que todas las macros se expandan PRIMERO y luego haga # o ## (en cuyo caso desea la indirección de doble capa) y en algún momento NO QUIERE que las macros se expandan primero (en las cuales Si NO PUEDE TENER macros de doble capa, debe hacerlo directamente.

__LINE__ es una macro especial que se supone que debe resolverse con el número de línea actual. Sin embargo, cuando se pega un token con __LINE__ directamente, no se puede resolver, por lo que se termina con el prefix__LINE__ del prefix__LINE__ lugar de, por ejemplo, el prefix23 , como si estuvieras esperando escribir este código en lo salvaje.

Chris Dodd tiene una excelente explicación para la primera parte de su pregunta. En cuanto a la segunda parte, sobre la secuencia de definición, la versión corta es que las directivas #define por sí mismas no se evalúan en absoluto; solo se evalúan y expanden cuando el símbolo se encuentra en otra parte del archivo. Por ejemplo:

 #define A a //adds A->a to the symbol table #define B b //adds B->b to the symbol table int A; #undef A //removes A->a from the symbol table #define AB //adds A->B to the symbol table int A; 

El primer int A; se convierte en int a; porque así es como A se define en ese punto en el archivo. El segundo int A; se convierte en int b; después de dos expansiones. Primero se expande a int B; porque A se define como B en ese punto del archivo. El preprocesador luego reconoce que B es una macro cuando verifica la tabla de símbolos. B luego se expande a b .

Lo único que importa es la definición del símbolo en el punto de expansión, independientemente de dónde esté la definición.

El orden en que se declaran las macros no es importante, el orden en que se utilizan es. Si tuvieras que usar esa macro antes de que se declarara (en el código actual, es decir, no en una macro que permanece latente hasta que se invoque), entonces obtendrías un error, pero como la mayoría de las personas sanas no van por ahí este tipo de cosas, escribir una macro y luego escribir una función que utiliza una macro aún no definida más abajo, etc., etc … Parece que su pregunta no es solo una pregunta sino que responderé esa parte. Creo que deberías haber roto esto un poco más.

La respuesta más no técnica, que reuní de todos los enlaces aquí, y el enlace de enlaces;) es que, una indirecta de una sola capa macro(x) #x corchea el nombre de la macro ingresada, pero al usar capas dobles, se stringify el valor de la macro ingresada.

 #define valueOfPi 3 #define macroHlp(x) #x #define macro(x) macroHlp(x) #define myVarOneLayer "Apprx. value of pi = " macroHlp(valueOfPi) #define myVarTwoLayers "Apprx. value of pi = " macro(valueOfPi) printf(myVarOneLayer); // out: Apprx. value of pi = valueOfPi printf(myVarOTwoLayers); // out: Apprx. value of pi = 3 

Qué sucede en printf(myVarOneLayer)

printf(myVarOneLayer) se expande a printf("Apprx. value of pi = " macroHlp(valueOfPi))

macroHlp(valueOfPi) intenta codificar la entrada, la entrada en sí no se evalúa. Su único propósito en la vida es tomar una entrada y stringify. Entonces se expande a "valueOfPi"

Entonces, ¿qué pasa en printf(myVarTwoLayers)

printf(myVarTwoLayers) se expande a printf("Apprx. value of pi = " macro(valueOfPi)

macro(valueOfPi) no tiene operación de stringificación, es decir, no hay #x en su expansión, pero hay una x , por lo que tiene que evaluar x e ingresar el valor a macroHlp para la cadena. Se expande a macroHlp(3) que a su vez codificará el número 3, ya que está usando #x