stdarg.h
es una cabecera en la biblioteca estándar de C del lenguaje de programación C que permite a las funciones que acepten un número indefinido de argumentos . [1] Proporciona facilidades para recorrer una lista de argumentos de función de tipo y número desconocido. C ++ proporciona esta funcionalidad en el encabezado cstdarg
.
El contenido de stdarg.h
se usa típicamente en funciones variadas , aunque pueden usarse en otras funciones (por ejemplo, vprintf
) llamadas por funciones variadas.
Declarar funciones variadas
Las funciones variables son funciones que pueden tomar un número variable de argumentos y se declaran con puntos suspensivos en lugar del último parámetro. Un ejemplo de tal función es printf
. Una declaración típica es
int check ( int a , double b , ...);
Las funciones variables deben tener al menos un parámetro con nombre, por ejemplo,
char * incorrecto (...);
no está permitido en C. (En C ++, esta declaración está permitida). En C, una coma debe preceder a los puntos suspensivos; en C ++, es opcional.
Definición de funciones variadas
Se utiliza la misma sintaxis en una definición:
long func ( char , double , int , ...); func long ( char a , double b , int c , ...) { / * ... * / }
Es posible que no aparezcan puntos suspensivos en las definiciones de funciones antiguas.
tipos stdarg.h
Nombre | Descripción | Compatibilidad |
---|---|---|
va_list | tipo para iterar argumentos | C89 |
macros stdarg.h
Nombre | Descripción | compatibilidad |
---|---|---|
va_start | Empiece a iterar argumentos con un va_list | C89 |
va_arg | Recuperar un argumento | C89 |
va_end | Libera un va_list | C89 |
va_copy | Copiar contenidos de uno va_list a otro | C99 |
Accediendo a los argumentos
Para acceder a los argumentos sin nombre, se debe declarar una variable de tipo va_list
en la función variadic. A va_start
continuación, se llama a la macro con dos argumentos: el primero es la variable declarada del tipo va_list
, el segundo es el nombre del último parámetro nombrado de la función. Después de esto, cada invocación de la va_arg
macro produce el siguiente argumento. El primer argumento de va_arg
es the va_list
y el segundo es el tipo del siguiente argumento que se pasa a la función. Finalmente, se va_end
debe llamar a la macro va_list
antes de que regrese la función. (No es necesario leer todos los argumentos).
C99 proporciona una macro adicional va_copy
, que puede duplicar el estado de un va_list
. La macro invocación se va_copy(va2, va1)
copia va1
en va2
.
No hay ningún mecanismo definido para determinar el número o los tipos de argumentos sin nombre que se pasan a la función. La función simplemente se requiere para saber o determinar esto de alguna manera, cuyos medios varían. Las convenciones comunes incluyen:
- Uso de una cadena de formato similar a
printf
oscanf
con especificadores incrustados que indican tipos de argumentos. - Un valor centinela al final de los argumentos variadic.
- Un argumento de recuento que indica el número de argumentos variados.
Pasar argumentos sin nombre a otras llamadas
Debido a que el tamaño de la lista de argumentos sin nombre generalmente se desconoce (las convenciones de llamada empleadas por la mayoría de los compiladores no permiten determinar el tamaño del bloque de argumentos sin nombre apuntado por va_list
dentro de la función receptora), tampoco existe una forma confiable y genérica de reenviar el argumentos sin nombre en otra función variádica. Incluso cuando es posible determinar el tamaño de la lista de argumentos por medios indirectos (por ejemplo, analizando la cadena de formato de fprintf()
), no hay una forma portátil de pasar el número de argumentos determinado dinámicamente a la llamada variada interna, como el número y el tamaño de los argumentos pasados a tales llamadas generalmente deben conocerse en tiempo de compilación. Hasta cierto punto, esta restricción se puede relajar empleando macros variadic en lugar de funciones variadic. Además, la mayoría de los procedimientos de biblioteca estándar proporcionan v
versiones alternativas prefijadas que aceptan una referencia a la lista de argumentos sin nombre (es decir, una va_list
variable inicializada ) en lugar de la lista de argumentos sin nombre en sí. Por ejemplo, vfprintf()
es una versión alternativa de fprintf()
esperar un en va_list
lugar de la lista de argumentos sin nombre real. Por lo tanto, una función variada definida por el usuario puede inicializar una va_list
variable utilizando va_start
y pasarla a una función de biblioteca estándar adecuada, pasando de hecho la lista de argumentos sin nombre por referencia en lugar de hacerlo por valor. Debido a que no existe una forma confiable de pasar listas de argumentos sin nombre por valor en C, proporcionar funciones de API variadas sin proporcionar también funciones equivalentes, aceptar en su va_list
lugar se considera una mala práctica de programación.
Tipo de seguridad
Algunas implementaciones de C proporcionan extensiones de C que permiten al compilador verificar el uso adecuado de cadenas de formato y centinelas. Salvo estas extensiones, el compilador generalmente no puede verificar si los argumentos sin nombre pasados son del tipo que espera la función, o convertirlos al tipo requerido. Por lo tanto, se debe tener cuidado para garantizar la corrección a este respecto, ya que se produce un comportamiento indefinido si los tipos no coinciden. Por ejemplo, si el tipo esperado es int *
, entonces se debe pasar un puntero nulo como (int *)NULL
. Escribir solo NULL
daría como resultado un argumento de tipo int
o void *
, ninguno de los cuales es correcto. Otra consideración son las promociones de argumentos predeterminadas aplicadas a los argumentos sin nombre. A float
se promoverá automáticamente a double
. Del mismo modo, los argumentos de tipos más estrechos que an int
serán promovidos a int
o unsigned int
. La función que recibe los argumentos sin nombre debe esperar el tipo promocionado.
GCC tiene una extensión que verifica los argumentos pasados:
format(archetype, string-index, first-to-check)
Los atributos especifica el formato que una función toma
printf
,scanf
,strftime
ostrfmon
argumentos de estilo que debe ser de tipo cotejan con una cadena de formato. Por ejemplo, la declaración:extern int my_printf ( void * my_object , const char * my_format , ...) __attribute__ (( formato ( printf , 2 , 3 )));hace que el compilador verifique los argumentos en las llamadas a
my_printf
para verificar su coherencia con elprintf
argumento de cadena de formato de estilomy_format
.- "5.27 Extensiones de la familia de lenguajes C - Declaración de atributos de funciones" . Consultado el 3 de enero de 2009 .
Ejemplo
#include #include / * imprime todos los argumentos uno a la vez hasta que se ve un argumento negativo; se supone que todos los argumentos son de tipo int * / void printargs ( int arg1 , ...) { va_list ap ; int i ; va_start ( ap , arg1 ); para ( i = arg1 ; i > = 0 ; i = va_arg ( ap , int )) printf ( "% d" , i ); va_end ( ap ); putchar ( '\ n' ); }int main ( vacío ) { printargs ( 5 , 2 , 14 , 84 , 97 , 15 , -1 , 48 , -1 ); printargs ( 84 , 51 , -1 , 3 ); printargs ( -1 ); printargs ( 1 , -1 ); return 0 ; }
Este programa produce la salida:
5 2 14 84 97 1584 511
Para llamar a otras funciones var args desde su función (como sprintf), debe usar la versión var arg de la función (vsprintf en este ejemplo):
void MyPrintf ( const char * formato , ...) { va_list args ; búfer char [ BUFSIZ ]; va_start ( args , formato ); vsnprintf ( tampón , sizeof tampón , formato , args ); va_end ( args ); FlushFunnyStream ( búfer ); }
varargs.h
Las versiones obsoletas de POSIX definieron el encabezado heredado varargs.h
, que data de antes de la estandarización de C y proporciona una funcionalidad similar a stdarg.h
. Este encabezado no forma parte de ISO C ni de POSIX. El archivo, como se define en la segunda versión de la Especificación Única de UNIX , simplemente contiene toda la funcionalidad de C89 stdarg.h
, con las excepciones que:
- no se puede utilizar en definiciones de estilo nuevo estándar de C
- el argumento dado puede omitirse (el estándar C requiere al menos un argumento)
La interfaz también es diferente. Por printargs
ejemplo, uno escribiría en su lugar:
#include #include / * No hay ningún tipo "vacío"; use un retorno int implícito. * / printargs ( arg1 , va_alist ) va_dcl / * ¡aquí no hay punto y coma! * / { va_list ap ; int i ; va_start ( ap ); para ( i = arg1 ; i > = 0 ; i = va_arg ( ap , int )) printf ( "% d" , i ); va_end ( ap ); putchar ( '\ n' ); volver ; }
y se llama de la misma manera.
varargs.h
requiere definiciones de funciones de estilo antiguo debido a la forma en que funciona la implementación. [2] Por el contrario, no es posible mezclar definiciones de funciones antiguas con stdarg.h
.
Referencias
- ^ "IEEE Std 1003.1
stdarg.h
" . Consultado el 4 de julio de 2009 . - ^ "Especificación UNIX única
varargs.h
" . Consultado el 1 de agosto de 2007 .