¿Cómo, exactamente, funciona el truco de la doble cadena?


84

Al menos algunos preprocesadores de C le permiten secuenciar el valor de una macro, en lugar de su nombre, pasándolo de una macro similar a una función a otra que la secuencia:

#define STR1(x) #x
#define STR2(x) STR1(x)
#define THE_ANSWER 42
#define THE_ANSWER_STR STR2(THE_ANSWER) /* "42" */

Ejemplos de casos de uso aquí .

Esto funciona, al menos en GCC y Clang (ambos con -std=c99), pero no estoy seguro de cómo funciona en términos estándar C.

¿Este comportamiento está garantizado por C99?
Si es así, ¿cómo lo garantiza C99?
Si no es así, ¿en qué punto pasa el comportamiento de definido por C a definido por GCC?


1
Si dice "al menos algunos", ¿significa que ha visto uno en el que no funciona? Estoy dispuesto a escribir un informe de error al proveedor.
Jens

@Jens: No; No tengo. Cada compilador que he usado (es decir, GCC y Clang) implementa este comportamiento.
Peter Hosey

Respuestas:


80

Sí, está garantizado.

Funciona porque los argumentos de las macros son en sí mismos macro expandidos, excepto cuando el nombre del argumento de la macro aparece en el cuerpo de la macro con el stringifier # o el token-paster ##.

6.10.3.1/1:

... Una vez que se han identificado los argumentos para la invocación de una macro de función, tiene lugar la sustitución de argumentos. Un parámetro en la lista de reemplazo, a menos que esté precedido por un token de preprocesamiento # o ## o seguido de un token de preprocesamiento ## (ver más abajo), se reemplaza por el argumento correspondiente después de que todas las macros contenidas en él se hayan expandido ...

Entonces, si lo hace STR1(THE_ANSWER), obtendrá "THE_ANSWER", porque el argumento de STR1 no está macroexpandido. Sin embargo, el argumento de STR2 se expande macro cuando se sustituye en la definición de STR2, que por lo tanto le da a STR1 un argumento de 42, con el resultado de "42".


21

Como señala Steve, esto está garantizado, y se ha garantizado desde el estándar C89, que era el estándar que codificaba los operadores # y ## en macros y obliga a expandir recursivamente macros en args antes de sustituirlos en el cuerpo si y solo si el cuerpo no aplica un # o ## al argumento. C99 no ha cambiado de C89 a este respecto.


+1 por tomarse el tiempo para confirmar que también es parte de C89. Algunos de nosotros nos preocupamos por la portabilidad, incluida la creación de código que las personas que compilan en modo C89 puedan usar; hace solo unos años, las versiones de gcc todavía tenían el valor predeterminado de C89 (más las extensiones de gcc para ser justos), la última vez que escuché que MSVC solo es compatible con C89 e integrado o los sistemas heredados también a veces solo tienen compiladores C89. C89 ofrece una gran portabilidad "planta baja", un estándar de mínimo común denominador al que las personas pueden apuntar para compilar y ejecutar para cualquier uso práctico actual. Así que es muy agradable verlo recordado.
mtraceur
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.