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 una función de este tipo es printf
. Respectivamente, las declaraciones y definiciones se realizan de manera similar.
int comprobar ( int a , doble b , ...); int comprobar ( int a , doble b , ...){ //... }
Según el estándar, las funciones varádicas sin parámetros nombrados no están permitidas 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.
Algunas declaraciones de funciones de estilo C de K&R no utilizan puntos suspensivos. [3]
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.Como el tamaño de la lista de argumentos sin nombre generalmente es desconocido, 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 normalmente no puede verificar si los argumentos sin nombre que se pasan 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 just 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. [ cita requerida ]
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ón scanf
: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 para my_printf
verificar la coherencia con el printf
formato de estilo del argumento de cadena my_format
[4]
#incluir <stdio.h> #incluir <stdarg.h> /*Obtener la suma de las variables*/ void suma ( int count , ...) { va_list ap ; int i = 0 ; int suma = 0 ; va_start ( ap , arg1 ); for ( i = 0 ; i < count ; i ++ ) suma += va_arg ( ap , int ); va_end ( ap ); return suma ; } int main ( void ) { printf ( "%i" , suma ( 2 , 1 , 3 )); devolver 0 ; }
Este programa debería obtener el siguiente resultado:
4
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. [5] Por el contrario, no es posible mezclar definiciones de funciones de estilo antiguo con stdarg.h
.