Pregunta

¿Por qué estos bloques de código producen resultados diferentes?

Algún código común:

#define PART1PART2 works
#define STRINGAFY0(s) #s
#define STRINGAFY1(s) STRINGAFY0(s)

caso 1:

#define GLUE(a,b,c) a##b##c  
STRINGAFY1(GLUE(PART1,PART2,*))
//yields
"PART1PART2*"

caso 2:

#define GLUE(a,b) a##b##*
STRINGAFY1(GLUE(PART1,PART2))
//yields
"works*"

caso 3:

#define GLUE(a,b) a##b
STRINGAFY1(GLUE(PART1,PART2*))
//yields
"PART1PART2*"

Estoy usando MSVC++ de VS.net 2005 sp1

Editar:Actualmente creo que el preprocesador funciona así al expandir macros:Paso 1:- Tome el cuerpo: elimine cualquier espacio en blanco alrededor de los operadores ## - analice la cadena, en el caso de que se encuentre un identificador que coincida con el nombre de un parámetro:-si está al lado de un operador ##, reemplace el identificador con el valor literal del parámetro (es decir,la cadena pasada) -Si no está al lado de un operador ##, ejecute todo este proceso de explicación en el valor del parámetro primero, luego reemplace el identificador con ese resultado.(Ignorando el stringfy sencillo '#' CASE ATM) -Remove a todos los operadores ##

Paso 2:- toma esa cadena resultante y analízala en busca de macros

ahora, a partir de eso creo que los 3 casos deberían producir exactamente la misma cadena resultante:

PARTE1PARTE2*

y por lo tanto, después del paso 2, debería resultar en

obras*

pero al menos debería resultar en lo mismo.

¿Fue útil?

Solución

Los casos 1 y 2 no tienen un comportamiento definido ya que estás tentado a pegar un * en un token de preprocesador.De acuerdo con las reglas de asociación de su preprocesador, esto intenta unir los tokens PART1PART2 (o solo PART2) y *.En su caso, esto probablemente falle silenciosamente, que es uno de los posibles resultados cuando las cosas no están definidas.la ficha PART1PART2 seguido por * entonces no volverá a ser considerado para la expansión macro.Stringfication luego produce el resultado que ve.

Mi gcc se comporta de manera diferente en tus ejemplos:

/usr/bin/gcc -O0 -g -std=c89 -pedantic   -E test-prepro.c
test-prepro.c:16:1: error: pasting "PART1PART2" and "*" does not give a valid preprocessing token
"works*"

Entonces, para resumir su caso 1, tiene dos problemas.

  • Pectar dos tokens que no dan como resultado un token preprocesador válido.
  • orden de evaluación de la ## operador

En el caso 3, su compilador da un resultado incorrecto.Debería

  1. evaluar los argumentos paraSTRINGAFY1
  2. para hacer eso tiene que expandirse GLUE
  3. GLUE resultados en PART1PART2*
  4. que debe ampliarse nuevamente
  5. el resultado es works*
  6. que luego se pasa aSTRINGAFY1

Otros consejos

Está haciendo exactamente lo que le está diciendo que haga.El primer y segundo toma los nombres de símbolos pasados y pegarlos juntos en un símbolo nuevo.El tercero lleva 2 símbolos y los pasta, luego está colocando el * en la cadena usted mismo (que eventualmente evaluará en otra cosa).

¿Cuál es exactamente la pregunta con los resultados?¿Qué esperabas obtener?Todo parece estar trabajando como lo esperaría.

¡Entonces, por supuesto, es la pregunta de por qué estás jugando con las artes oscuras del símbolo munging como este de todos modos?:)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top