# y ## en macros

2 minutos de lectura

avatar de usuario
algo-geeks

  #include <stdio.h>
  #define f(a,b) a##b
  #define g(a)   #a
  #define h(a) g(a)

  int main()
  {
    printf("%s\n",h(f(1,2)));
    printf("%s\n",g(f(1,2)));
    return 0;
  }

Con solo mirar el programa, uno “podría” esperar que la salida sea la misma para ambas declaraciones printf. Pero al ejecutar el programa lo obtienes como:

bash$ ./a.out
12
f(1,2)
bash$

¿Por que es esto entonces?

Una ocurrencia de un parámetro en una macro similar a una función, a menos que sea el operando de # o ##, se expande antes de sustituirlo y volver a escanear el conjunto para una mayor expansión. Porque gparámetro de es el operando de #el argumento no se expande sino que se encadena inmediatamente ("f(1,2)"). Porque hparámetro de no es el operando de # ni ##el argumento se expande primero (12), luego sustituyó (g(12)), luego se vuelve a escanear y se produce una mayor expansión ("12").

avatar de usuario
cristooferta

Porque así es como funciona el preprocesador.

Un solo ‘#’ creará una cadena a partir del argumento dado, independientemente de lo que contenga ese argumento, mientras que el doble ‘##’ creará un nuevo token concatenando los argumentos.

Intente mirar la salida preprocesada (por ejemplo, con gcc -E) si desea comprender mejor cómo se evalúan las macros.

  • Creo que la pregunta es más sobre cómo h(f(1,2)) y g(f(1,2)) diferir de. En ese sentido, la respuesta de @joe-bloggs es más clara.

    – Vsévolod Ganin

    18 mayo 2019 a las 17:34

  • hola que tal si #define STR "AAA " #define f(a) (STR#a) voluntad f(BBB) ser "AAA ""BBB" o "AAA BBB"? ¿Puede este soltero # en medio de cadenas concatenar argumentos?

    – leoleohu

    13 de mayo de 2021 a las 7:58


avatar de usuario
smwikipedia

A continuación se presentan algunos conceptos relacionados con su pregunta:

argumento preescaneado:

Los argumentos de macro están completamente macro-expandidos antes de se sustituyen en un cuerpo macro, a menos que sean encadenado o pegado

con otras fichas. Después de la sustitución, se escanea todo el cuerpo de la macro, incluidos los argumentos sustituidos. otra vez para que se expandan las macros. El resultado es que los argumentos se escanean dos veces para expandir las llamadas de macro en ellos.

Stringificación

Cuando se usa un parámetro de macro con un ‘#’ inicial, el preprocesador lo reemplaza con el texto literal del argumento real, convertido a un constante de cadena.

#ABC => "ABC" <---- Tenga en cuenta las comillas dobles adjuntas, que se agregan mediante el proceso de encadenamiento.

Pegado de tokens / Concatenación de tokens:

A menudo es útil fusionar dos tokens en uno mientras se expanden las macros. Se llama pegado de fichas o concatenación de tokens. El operador de preprocesamiento ‘##’ realiza el pegado de tokens. Cuando se expande una macro, los dos tokens a cada lado de cada operador ‘##’ se combinan en un solo token, que luego reemplaza el ‘##’ y los dos tokens originales en la expansión de la macro.

Entonces, el proceso detallado de su escenario es así:

h(f(1,2))
-> h(12) // f(1,2) pre-expanded since there's no # or ## in macro h
-> g(12)  // h expanded to g
"12"   // g expanded as Stringification

g(f(1,2))
-> "f(1,2)"  //f(1,2) is literally strigified because of the `#` in macro g. f(1,2) is NOT expanded at all.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad