Replacing text macros
El preprocesador admite el reemplazo de macros de texto. También se admite el reemplazo de macros de texto similares a funciones.
Contenido
Sintaxis
Explicación
#define directivasLas directivas #define definen el identifier como macro, es decir, instruyen al compilador para reemplazar la mayoría de las ocurrencias sucesivas de identifier con replacement-list , que será procesado adicionalmente. Las excepciones surgen de las reglas de scanning and replacement . Si el identifier ya está definido como cualquier tipo de macro, el programa está mal formado a menos que las definiciones sean idénticas. Macros similares a objetosLas macros similares a objetos reemplazan cada aparición del identificador definido con la lista-de-reemplazo . La versión (1) de la directiva #define se comporta exactamente de esa manera. Macros similares a funcionesLas macros similares a funciones reemplazan cada aparición del identificador definido con la lista-de-reemplazo , tomando adicionalmente un número de argumentos, que luego reemplazan las apariciones correspondientes de cualquiera de los parámetros en la lista-de-reemplazo . La sintaxis de una invocación de macro similar a una función es similar a la sintaxis de una llamada a función: cada instancia del nombre de la macro seguida por un ( como el siguiente token de preprocesamiento introduce la secuencia de tokens que es reemplazada por la replacement-list . La secuencia termina con el token coincidente ) , omitiendo pares coincidentes intermedios de paréntesis izquierdos y derechos.
Para la versión (2), el número de argumentos debe ser el mismo que el número de parámetros en la definición de macro. Para las versiones (3,4), el número de argumentos no debe ser menor que el número de parámetros (
no
(desde C++20)
contando
La versión (2) de la directiva #define define una macro simple similar a una función.
La versión (3) de la directiva
#define
define una macro similar a función con número variable de argumentos. Los argumentos adicionales (llamados
argumentos variables
) pueden accederse usando el identificador
La versión (4) de la directiva
#define
define una macro similar a una función con número variable de argumentos, pero sin argumentos regulares. Los argumentos (llamados
argumentos variables
) solo pueden accederse con el identificador
Nota: si un argumento de una macro similar a una función incluye comas que no están protegidas por pares coincidentes de paréntesis izquierdos y derechos (más comúnmente encontradas en listas de argumentos de plantilla, como en assert ( std:: is_same_v < int , int > ) ; o BOOST_FOREACH ( std:: pair < int , int > p, m ) ), la coma se interpreta como separador de argumentos de macro, causando un fallo de compilación debido a discrepancia en el número de argumentos. Escaneo y Reemplazo
Nota, es posible definir una macro pseudo recursiva:
Ejecutar este código
#define EMPTY #define SCAN(x) x #define EXAMPLE_() EXAMPLE #define EXAMPLE(n) EXAMPLE_ EMPTY()(n-1) (n) EXAMPLE(5) SCAN(EXAMPLE(5)) Salida: EXAMPLE_ ()(5 -1) (5) EXAMPLE_ ()(5 -1 -1) (5 -1) (5) Nombres de macros reservadosUna unidad de traducción que incluye un encabezado de la biblioteca estándar no puede #define o #undef nombres declarados en cualquier encabezado de la biblioteca estándar . Una unidad de traducción que utiliza cualquier parte de la biblioteca estándar no puede #define o #undef nombres léxicamente idénticos a:
De lo contrario, el comportamiento es indefinido.
# y ## operadoresEn macros similares a funciones, un operador # antes de un identificador en la replacement-list procesa el identificador mediante reemplazo de parámetros y lo encierra entre comillas, creando efectivamente un literal de cadena. Además, el preprocesador añade barras invertidas para escapar las comillas que rodean los literales de cadena incrustados, si los hay, y duplica las barras invertidas dentro de la cadena según sea necesario. Se eliminan todos los espacios en blanco iniciales y finales, y cualquier secuencia de espacios en blanco en medio del texto (pero no dentro de literales de cadena incrustados) se reduce a un solo espacio. Esta operación se denomina "stringification". Si el resultado de la stringification no es un literal de cadena válido, el comportamiento es indefinido.
Un operador
##
entre dos identificadores sucesivos en la
lista-de-reemplazo
ejecuta el reemplazo de parámetros en los dos identificadores (que no se expanden primero como macros) y luego concatena el resultado. Esta operación se denomina "concatenación" o "pegado de tokens". Solo los tokens que forman un token válido juntos pueden pegarse: identificadores que forman un identificador más largo, dígitos que forman un número, u operadores
Nota: algunos compiladores ofrecen una extensión que permite que
##
aparezca después de una coma y antes de
#undef directivaLa directiva #undef anula la definición del identificador , es decir, cancela la definición previa del identificador realizada por la directiva #define . Si el identificador no tiene una macro asociada, la directiva se ignora. Macros predefinidasLos siguientes nombres de macro están predefinidos en cada unidad de traducción:
Los siguientes nombres de macro adicionales pueden estar predefinidos por las implementaciones:
Los valores de estas macros (excepto
Ejemplo
Ejecutar este código
#include <iostream> // Crear fábrica de funciones y usarla #define FUNCTION(name, a) int fun_##name() { return a; } FUNCTION(abcd, 12) FUNCTION(fff, 2) FUNCTION(qqq, 23) #undef FUNCTION #define FUNCTION 34 #define OUTPUT(a) std::cout << "output: " #a << '\n' // Usando una macro en la definición de una macro posterior #define WORD "Hello " #define OUTER(...) WORD #__VA_ARGS__ int main() { std::cout << "abcd: " << fun_abcd() << '\n'; std::cout << "fff: " << fun_fff() << '\n'; std::cout << "qqq: " << fun_qqq() << '\n'; std::cout << FUNCTION << '\n'; OUTPUT(million); //nótese la falta de comillas std::cout << OUTER(World) << '\n'; std::cout << OUTER(WORD World) << '\n'; } Salida: abcd: 12 fff: 2 qqq: 23 34 output: million Hello World Hello WORD World Informes de defectosLos siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.
Véase también
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||