va_arg, va_end, va_start

Access variable-argument lists.

type va_arg( 
   va_list arg_ptr, 
   type  
); 
void va_end( 
   va_list arg_ptr  
); 
void va_start( 
   va_list arg_ptr, 
   prev_param  
); // (ANSI version)
void va_start( 
   arg_ptr  
);  // (Pre-ANSI-standardization version)

Parameters

  • type
    Type of argument to be retrieved.

  • arg_ptr
    Pointer to list of arguments.

  • prev_param
    Parameter preceding first optional argument (ANSI only).

Return Value

va_arg returns the current argument; va_start and va_end do not return values.

Remarks

The va_arg, va_end, and va_start macros provide a portable way to access the arguments to a function when the function takes a variable number of arguments. Two versions of the macros are available: The macros defined in STDARG.H conform to the ANSI C standard. The macros defined in VARARGS.H are obsolete and remain for backwards compatibility. They were designed for use before ANSI standardization.

These macros assume that the function takes a fixed number of required arguments, followed by a variable number of optional arguments. The required arguments are declared as ordinary parameters to the function and can be accessed through the parameter names. The optional arguments are accessed through the macros in STDARG.H or VARARGS.H, which set a pointer to the first optional argument in the argument list, retrieve arguments from the list, and reset the pointer when argument processing is completed.

The ANSI C standard macros, defined in STDARG.H, are used as follows:

  • va_start sets arg_ptr to the first optional argument in the list of arguments passed to the function. The argument arg_ptr must have va_list type. The argument prev_param is the name of the required parameter immediately preceding the first optional argument in the argument list. If prev_param is declared with the register storage class, the macro's behavior is undefined. va_start must be used before va_arg is used for the first time.

  • va_arg retrieves a value of type from the location given by arg_ptr and increments arg_ptr to point to the next argument in the list, using the size of type to determine where the next argument starts. va_arg can be used any number of times within the function to retrieve arguments from the list.

  • After all arguments have been retrieved, va_end resets the pointer to NULL.

C++ noteC++ Note:

The macros defined in VARARGS.H are deprecated and exist solely for backwards compatibility. Use the macros defined in STDARGS.H unless you are working with code before the ANSI standard.

When compiled with /clr (Common Language Runtime Compilation), programs using these macros may generate unexpected results because of differences between native and common language runtime type systems. Consider this program:

#include <stdio.h>
#include <stdarg.h>

void testit ( int i, ...)
{
   va_list argptr;
   va_start(argptr, i);

   if ( i == 0 ) {
      int n = va_arg( argptr, int );
      printf( "%d\n", n );
   } else {
      char *s = va_arg( argptr, char* );
      printf( "%s\n", s);
   }
}

int main()
{
   testit( 0, 0xFFFFFFFF ); // 1st problem: 0xffffffff is not an int
   testit( 1, NULL );       // 2nd problem: NULL is not a char*
}

Note that testit expects its second parameter to be either an int or a char*. The arguments being passed are 0xffffffff (an unsigned int, not an int) and NULL (actually an int, not a char*). When compiled for native code, the program produces the output

-1
(null)

However, when compiled with /clr:pure, the type mismatches cause the program to generate an exception. The solution is to use explicit casts:

int main()
{
   testit( 0, (int)0xFFFFFFFF ); // cast unsigned to int
   testit( 1, (char*)NULL );     // cast int to char*
}

Requirements

Header: <stdio.h> and <stdarg.h>

Legacy Header: <varargs.h>

Libraries

All versions of the C run-time libraries.

Example

// crt_va.c
/* The program below illustrates passing a variable
 * number of arguments using the following macros:
 *      va_start            va_arg              va_end
 *      va_list
 */

#include <stdio.h>
#include <stdarg.h>
int average( int first, ... );

int main( void )
{
   /* Call with 3 integers (-1 is used as terminator). */
   printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );

   /* Call with 4 integers. */
   printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );

   /* Call with just -1 terminator. */
   printf( "Average is: %d\n", average( -1 ) );
}

/* Returns the average of a variable list of integers. */
int average( int first, ... )
{
   int count = 0, sum = 0, i = first;
   va_list marker;

   va_start( marker, first );     /* Initialize variable arguments. */
   while( i != -1 )
   {
      sum += i;
      count++;
      i = va_arg( marker, int);
   }
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}

Output

Average is: 3
Average is: 8
Average is: 0

.NET Framework Equivalent

System::ParamArrayAttribute Class

See Also

Reference

Argument Access

vfprintf, _vfprintf_l, vfwprintf, _vfwprintf_l

Change History

Date

History

Reason

January 2011

Clarified the information about the pre-ANSI standardization version.

Customer feedback.