Una macro variadic es una característica de algunos lenguajes de programación de computadoras , especialmente el preprocesador de C , por el cual una macro puede declararse para aceptar un número variable de argumentos .
Las macros de argumentos variables se introdujeron en 1999 en la revisión ISO / IEC 9899: 1999 ( C99 ) del estándar del lenguaje C , y en 2011 en la revisión ISO / IEC 14882: 2011 ( C ++ 11 ) del estándar del lenguaje C ++ . [1] Se agregó soporte para macros variadic sin argumentos en C ++ 20 . [2]
Sintaxis de declaración
La sintaxis de declaración es similar a la de las funciones variadic : una secuencia de tres puntos y aparte " ... " se utiliza para indicar que se deben pasar uno o más argumentos. Durante la expansión de macros, cada aparición del identificador especial __VA_ARGS__ en la lista de reemplazo de macros se reemplaza por los argumentos pasados.
No se proporciona ningún medio para acceder a argumentos individuales en la lista de argumentos de variable, ni para averiguar cuántos se pasaron. Sin embargo, se pueden escribir macros para contar el número de argumentos que se han pasado. [3]
Tanto los estándares C99 como C ++ 11 requieren al menos un argumento, pero desde C ++ 20 esta limitación se ha eliminado mediante la macro funcional __VA_OPT__ . La macro __VA_OPT__ se reemplaza por su argumento cuando hay argumentos presentes y se omite en caso contrario. Sin embargo, los compiladores comunes también permiten pasar argumentos cero antes de esta adición. [4] [5]
Las reglas del preprocesador de C evitan que los nombres de macro en el argumento de __VA_OPT__ se expandan de forma recursiva. Sin embargo, es posible evitar esta limitación hasta un número fijo arbitrario de expansiones recursivas. [6]
Apoyo
Varios compiladores admiten macros de argumentos variables al compilar código C y C ++: GNU Compiler Collection 3.0, [4] Clang (todas las versiones), [7] Visual Studio 2005 , [5] C ++ Builder 2006 y Oracle Solaris Studio ( anteriormente Sun Studio) Forte Developer 6 actualización 2 (C ++ versión 5.3). [8] GCC también admite este tipo de macros al compilar Objective-C .
Se ha agregado compatibilidad con la macro __VA_OPT__ para admitir argumentos cero en GNU Compiler Collection 8, [9] Clang 6, [10] y Visual Studio 2019 . [11]
Ejemplo
Si se desea una funciónprintf
similar a , que tomaría el archivo y el número de línea desde el que se llamó como argumentos, se aplica la siguiente solución. dbgprintf()
// Nuestra función implementada void realdbgprintf ( const char * SourceFilename , int SourceLineno , const char * CFormatString , ...);// Debido a las limitaciones del soporte de macro variadic en C ++ 11, la siguiente // solución sencilla puede fallar y, por lo tanto, debe evitarse: // // #define dbgprintf (cformat, ...) \ // realdbgprintf (__FILE__, __LINE__, cformat, __VA_ARGS__) // // La razón es que // // dbgprintf ("Hallo") // // se expande a // // realdbgprintf (__FILE__, __LINE__, "Hallo",) // // donde la coma antes de la llave de cierre dará como resultado un error de sintaxis. // // GNU C ++ admite una extensión no portátil que resuelve esto. // // #define dbgprintf (cformat, ...) \ // realdbgprintf (__FILE__, __LINE__, cformat, ## __ VA_ARGS__) // // C ++ 20 eventualmente admite la siguiente sintaxis. // // #define dbgprintf (cformat, ...) \ // realdbgprintf (__FILE__, __LINE__, cformat __VA_OPT __ (,) __VA_ARGS__) // // Usando la cadena 'cformat' como parte de los argumentos variadic podemos / / eludir las incompatibilidades antes mencionadas. Esto es complicado pero // portátil. #define dbgprintf (...) realdbgprintf (__FILE__, __LINE__, __VA_ARGS__)
dbgprintf()
entonces podría llamarse como
dbgprintf ( "Hola, mundo" );
que se expande a
realdbgprintf ( __FILE__ , __LINE__ , "Hola, mundo" );
Otro ejemplo es
dbgprintf ( "% d +% d =% d" , 2 , 2 , 5 );
que se expande a
realdbgprintf ( __FILE__ , __LINE__ , "% d +% d =% d" , 2 , 2 , 5 );
Sin macros variadic, escribir envoltorios en printf
no es directamente posible. La solución estándar es utilizar la funcionalidad estándar de C / C ++ y, en su lugar, tener la llamada a la función vprintf
.
Coma final
Existe un problema de portabilidad al generar una coma al final con argumentos vacíos para macros variadic en C99 . Algunos compiladores (por ejemplo, Visual Studio cuando no se utiliza el nuevo preprocesador conforme al estándar [5] ) eliminarán silenciosamente la coma final. Otros compiladores (por ejemplo: GCC [4] ) admiten la puesta ##
delante de __VA_ARGS__ .
# define MYLOG (FormatLiteral, ...) fprintf (stderr, "% s (% u):" FormatLiteral "\ n", __FILE__, __LINE__, __VA_ARGS__)
La siguiente aplicación funciona
MYLOG ( "Demasiados globos% u" , 42 );
que se expande a
fprintf ( stderr , "% s (% u):" "Demasiados globos% u" " \ n " , __FILE__ , __LINE__ , 42 );
que es equivalente a
fprintf ( stderr , "% s (% u): Demasiados globos% u \ n " , __FILE__ , __LINE__ , 42 );
Pero mira esta aplicación:
MYLOG ( "¡Atención!" );
que se expande a
fprintf ( stderr , "% s (% u):" "¡Atención!" " \ n " , __FILE__ , __LINE__ , );
que genera un error de sintaxis con GCC.
GCC admite la siguiente extensión (no portátil):
# define MYLOG (FormatLiteral, ...) fprintf (stderr, "% s (% u):" FormatLiteral "\ n", __FILE__, __LINE__, ## __ VA_ARGS__)
que elimina la coma final cuando __VA_ARGS__ está vacío.
Alternativas
Antes de la existencia de argumentos variables en C99, era bastante común usar paréntesis doblemente anidados para explotar el número variable de argumentos que se podían suministrar a la printf()
función:
# definir dbgprintf (x) realdbgprintf x
dbgprintf()
entonces podría llamarse como:
dbgprintf (( "Hola, mundo% d" , 27 ));
que se expande a:
realdbgprintf ( "Hola, mundo% d" , 27 );
Referencias
- ^ Cambios en el borrador de trabajo para la sincronización del preprocesador C99 - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm
- ^ "Omisión de coma y eliminación de coma" . 12 de julio de 2017 . Consultado el 14 de junio de 2018 .
- ^ Laurent Deniau (16 de enero de 2006). "__VA_NARG__" . Grupo de noticias : comp.std.c . Usenet: [email protected] .
- ^ a b c Macros variables: uso de la colección de compiladores GNU (GCC)
- ^ a b c Macros variables (C ++)
- ^ Macros recursivas con C ++ 20 __VA_OPT__
- ^ Cambio de código fuente de Clang que menciona el soporte de __VA_ARGS__ (2006-07-29), tenga en cuenta que Clang fue de código abierto en 2007. http://llvm.org/viewvc/llvm-project?view=revision&revision=38770
- ^ Comparación de funciones de Sun Studio: http://developers.sun.com/sunstudio/support/CCcompare.html
- ^ "Soporte C ++ 2a en GCC" . Consultado el 14 de junio de 2018 .
- ^ "Soporte C ++ en Clang" . Consultado el 14 de junio de 2018 .
- ^ "Descripción general del nuevo preprocesador de MSVC" . 10 de septiembre de 2020 . Consultado el 8 de diciembre de 2020 .
Ver también
- Función variádica
- Plantilla variadic