with macro language ejemplo define __va_args__ macros c-preprocessor

macros - macro - define max en c



¿Por qué se reemplaza esta macro como 20 en lugar de 10? (4)

El estándar C11 dice (y otras versiones de C y C ++, dicen de manera similar):

Una directiva de preprocesamiento de la forma # define identifier replacement-list new-line define una macro similar a un objeto que hace que cada instancia posterior del nombre de macro sea reemplazada por la lista de reemplazo de tokens de preprocesamiento que constituyen el resto de la directiva. La lista de reemplazo se vuelve a explorar para obtener más nombres de macro como se especifica a continuación.

Sin embargo, también lo dice en otra parte (gracias a rici por señalar esto).

Los tokens de preprocesamiento dentro de una directiva de preprocesamiento no están sujetos a expansión macro a menos que se indique lo contrario.

Por lo tanto, una instancia posterior del nombre de macro que se encuentra dentro de otra directiva #define realidad no se reemplaza.

Su línea #define FOO NUM define que cuando el token FOO se encuentre más tarde (fuera de otra directiva #define !), Será reemplazado por el token NUM .

Después de reemplazar un token, se produce un nuevo escaneo , y si NUM es en sí mismo una macro, entonces NUM se reemplaza en ese punto. (Y si lo que NUM expande contiene macros, entonces eso se expande, y así sucesivamente).

Entonces su secuencia de pasos es en realidad:

  1. NUM definido como 10
  2. FOO definido como NUM
  3. NUM indefinido y redefinido como 20
  4. FOO expande a NUM
  5. (reescanear) NUM expande a 20

Este comportamiento se puede ver en otro truco común del preprocesador, para convertir el valor definido de una macro en una cadena:

#define STR(X) #X #define STR_MACRO(X) STR(X) #define NUM 10 puts( STR_MACRO(NUM) ); // output: 10

Si hubiéramos escrito puts( STR(NUM) ) , la salida sería NUM .

La salida de 10 es posible porque, como antes, el segundo #define aquí en realidad no expande STR . Entonces, la secuencia de pasos en este código es:

  1. STR(X) definido como #X
  2. STR_MACRO(X) definido como STR(X)
  3. NUM definido como 10
  4. STR_MACRO y NUM están expandidos; el resultado es puts( STR(10) );
  5. (Resultado de reescaneo de la última expansión) STR(10) se expande a "10"
  6. (Volver a analizar el resultado de la última expansión) No es posible una expansión adicional.

1. #define NUM 10 2. #define FOO NUM 3. #undef NUM 4. #define NUM 20 5. 6. FOO

Cuando solo ejecuto el preprocesador, el archivo de salida contiene 20.

Sin embargo, por lo que entiendo, el preprocesador simplemente reemplaza el texto. Entonces, esto es lo que creo que está sucediendo (lo cual obviamente es incorrecto pero idky):

  1. NUM se define como 10.
  2. Por lo tanto, en la línea 2, NUM se reemplaza como 10. Entonces ahora tenemos "#define FOO 10".
  3. NUM no está definido.
  4. NUM está redefinido y ahora es 20.
  5. FOO se reemplaza de acuerdo con la línea 2, que era antes de la redefinición de la línea 4, y es 10.

Así que creo que la salida debería ser 10 en lugar de 20. ¿Algo puede explicar dónde salió mal?


El reemplazo de texto se realiza donde se usa la macro, no donde escribió el #define . En el momento en que usa FOO , reemplaza FOO con NUM y NUM se define actualmente como 20 .


En el interés de recopilar todas las especificaciones relevantes de los estándares, extraje esta información de un hilo de comentarios y agregué números de sección C ++, basados ​​en el borrador N4527 (el texto normativo es idéntico en los dos estándares). Los estándares son absolutamente claros sobre el tema.

  1. #define directivas de preprocesador no se someten a reemplazo de macro.

    (C11 §6.10¶7; C ++ §16 [cpp] ¶6): los tokens de preprocesamiento dentro de una directiva de preprocesamiento no están sujetos a expansión macro a menos que se indique lo contrario.

  2. Después de reemplazar una macro con su texto de reemplazo, el nuevo texto se vuelve a explorar. Los tokens de preprocesador en el reemplazo se expanden como macros si hay una definición de macro activa para el token en ese punto del programa.

    (C11 §6.10.3¶9; C ++ §16.3 [cpp.replace] ¶9) Una directiva de preprocesamiento del formulario

    # define identifier replacement-list new-line

    define una macro similar a un objeto que hace que cada instancia posterior del nombre de la macro sea reemplazada por la lista de reemplazo de tokens de preprocesamiento que constituyen el resto de la directiva. La lista de reemplazo se vuelve a explorar para obtener más nombres de macro como se especifica a continuación.

  3. Una definición de macro está activa desde la línea que sigue al #define hasta un #undef para el nombre de la macro o al final del archivo.

    (C11 §6.10.3.5¶1; C ++ §16.3.5 [cpp.scope] ¶1) Una definición de macro dura (independientemente de la estructura del bloque) hasta que se encuentre una directiva #undef correspondiente o (si no se encuentra ninguna) hasta el final de la unidad de traducción de preprocesamiento. Las definiciones de macro no tienen importancia después de la fase de traducción 4.

Si miramos el programa:

#define NUM 10 #define FOO NUM #undef NUM #define NUM 20 FOO

vemos que la definición macro de NUM en la línea 1 dura exactamente hasta la línea 3. No hay texto reemplazable en esas líneas, por lo que la definición nunca se usa; en consecuencia, el programa es efectivamente el mismo que:

#define FOO NUM #define NUM 20 FOO

En este programa, en la tercera línea, hay una definición activa para FOO , con la lista de reemplazo NUM , y para NUM , con la lista de reemplazo 20 . El FOO se reemplaza con su lista de reemplazo, convirtiéndolo en NUM , y luego se escanea una vez más en busca de macros, lo que resulta en NUM reemplazado por su lista de reemplazo 20. Ese reemplazo se vuelve a explorar, pero no hay macros definidas, por lo que el final El resultado es que el token 20 se deja para procesar en la fase de traducción 5.


En:

FOO

el preprocesador lo reemplazará con NUM , luego reemplazará NUM con lo que actualmente se define, que es 20 .

Esas cuatro líneas iniciales son equivalentes a:

#define FOO NUM #define NUM 20