Este artículo está escrito como un manual o una guía . ( Octubre de 2013 ) |
Biblioteca estándar de C (libc) |
---|
Temas generales |
Encabezados varios |
stdarg.h
es un encabezado en la biblioteca estándar C del lenguaje de programación C que permite que las funciones acepten un número indefinido de argumentos . [1] Proporciona facilidades para recorrer una lista de argumentos de función de número y tipo desconocidos. C++ proporciona esta funcionalidad en el encabezado cstdarg
.
Los contenidos de stdarg.h
se utilizan normalmente en funciones variádicas , aunque pueden usarse en otras funciones (por ejemplo, vprintf
) llamadas por funciones variádicas.
Las funciones variádicas son funciones que pueden tomar una cantidad variable de argumentos y se declaran con puntos suspensivos en lugar del último parámetro. Un ejemplo de este tipo de función es printf
. Una declaración típica es
int comprobar ( int a , doble b , ...);
Las funciones variádicas deben tener al menos un parámetro nombrado, así, por ejemplo,
char * incorrecto (...);
no está permitido en C17 y anteriores, pero en C++ y C23 [2] tal declaración está permitida.
En C, una coma debe preceder a los puntos suspensivos si se especifica un parámetro con nombre, mientras que en C++ es opcional.
La misma sintaxis se utiliza en una definición:
función larga ( char , doble , int , ...); función larga ( char a , doble b , int c , ...) { /* ... */ }
Es posible que no aparezcan puntos suspensivos en las definiciones de funciones de estilo antiguo.
Nombre | Descripción | Compatibilidad |
---|---|---|
va_list | tipo para iterar argumentos | C89 |
Nombre | Descripción | compatibilidad |
---|---|---|
va_start | Comience a iterar argumentos con unva_list | C89 |
va_arg | Recuperar un argumento | C89 |
va_end | Gratis ava_list | C89 |
va_copy | Copiar el contenido de uno va_list a otro | C99 |
Según el estándar, para acceder a los argumentos sin nombre se puede hacer a través de una variable de tipo va_list
en la función variádica, con macro va_start
también proporcionada como el último parámetro nombrado de la función. En C23 el segundo argumento es opcional y no será evaluado [2] . Después de esto, cada invocación de la va_arg
macro produce el siguiente argumento. El primer argumento va_arg
es va_list
y el segundo es el tipo del siguiente argumento pasado a la función. Como último paso, la va_end
macro debe ser llamada en va_list
antes de que la función regrese. Tenga en cuenta que no es necesario leer todos los argumentos.
C99 proporciona una macro adicional, va_copy
, que puede duplicar el estado de un va_list
. La invocación de la macro va_copy(va2, va1)
copia va1
en va2
.
No existe un método definido para contar o clasificar los argumentos sin nombre que se pasan a la función variádica. La función simplemente debería determinar esto de alguna manera, cuyos medios varían. Las convenciones comunes incluyen:
printf
a o scanf
con especificadores integrados que indican tipos de argumentos.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 al que apunta va_list
dentro de la función receptora. Como resultado, tampoco hay una forma genérica y confiable de reenviar los argumentos sin nombre a 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 variádica interna, ya que el número y el tamaño de los argumentos pasados a dichas llamadas generalmente deben conocerse en el momento de la compilación. Hasta cierto punto, esta restricción se puede relajar empleando macros variádicas en lugar de funciones variádicas. Además, la mayoría de los procedimientos de la biblioteca estándar proporcionan v
versiones alternativas con prefijo - 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 a va_list
en lugar de la lista de argumentos sin nombre real. Por lo tanto, una función variádica definida por el usuario puede inicializar una va_list
variable mediante 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 API variádicas sin proporcionar también funciones equivalentes que acepten va_list
en su lugar se considera una mala práctica de programación.
Algunas implementaciones de C proporcionan extensiones de C que permiten al compilador verificar el uso correcto 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 la función espera, o convertirlos al tipo requerido. Por lo tanto, se debe tener cuidado para garantizar la corrección en este sentido, 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 que se aplican a los argumentos sin nombre. A float
se promoverá automáticamente a a double
. Del mismo modo, los argumentos de tipos más estrechos que an int
se promoverán 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)
El atributo de formato especifica que una función acepta argumentos
printf
, o style que deben comprobarse en función del tipo con una cadena de formato. Por ejemplo, la declaraciónscanf
:strftime
strfmon
extern int my_printf ( void * mi_objeto , const char * mi_formato , ...) __atributo__ (( formato ( printf , 2 , 3 )));hace que el compilador verifique los argumentos en las llamadas a
my_printf
para verificar su coherencia con elprintf
formato de estilo de la cadena de argumentosmy_format
.— "5.27 Extensiones de la familia de lenguajes C - Declaración de atributos de funciones" . Consultado el 3 de enero de 2009 .
#incluir <stdio.h> #incluir <stdarg.h> /* imprime todos los argumentos uno a uno hasta que se vea 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 ( void ) { imprimirargs ( 5 , 2 , 14 , 84 , 97 , 15 , -1 , 48 , -1 ); imprimirargs ( 84 , 51 , -1 , 3 ); imprimirargs ( -1 ); imprimirargs ( 1 , -1 ); devolver 0 ; }
Este programa produce el siguiente resultado:
5 2 14 84 97 1584 511
Para llamar a otras funciones var args desde dentro de su función (como sprintf), debe usar la versión var arg de la función (vsprintf en este ejemplo):
void MyPrintf ( const char * format , ...) { va_list args ; char buffer [ BUFSIZ ]; va_start ( argumentos , formato ); vsnprintf ( búfer , tamaño del búfer , formato , argumentos ); va_end ( argumentos ); FlushFunnyStream ( búfer ); }
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 es parte de ISO C ni de POSIX. El archivo, tal 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:
La interfaz también es diferente. Por printargs
ejemplo, se podría escribir:
#include <stdio.h> #include <varargs.h> /* No hay ningún tipo "void"; 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 ); /* ¡solo se proporciona la va_list! */ for ( i = arg1 ; i >= 0 ; i = va_arg ( ap , int )) printf ( "%d" , i ); va_end ( ap ); putchar ( '\n' ); return ; }
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. [3] Por el contrario, no es posible mezclar definiciones de funciones de estilo antiguo con stdarg.h
.