stdarg, va_start, va_arg, va_end, va_copy − variable argument lists


#include <stdarg.h>

void va_start(va_list ap, last);
va_arg(va_list ap, type);
void va_end(va_list
void va_copy(va_list
dest, va_list src);


A function may be called with a varying number of arguments of varying types. The include file <stdarg.h> declares a type va_list and defines three macros for stepping through a list of arguments whose number and types are not known to the called function.

The called function must declare an object of type va_list which is used by the macros va_start(), va_arg(), and va_end().

The va_start() macro initializes ap for subsequent use by va_arg() and va_end(), and must be called first.

The argument last is the name of the last argument before the variable argument list, that is, the last argument of which the calling function knows the type.

Because the address of this argument may be used in the va_start() macro, it should not be declared as a register variable, or as a function or an array type.

The va_arg() macro expands to an expression that has the type and value of the next argument in the call. The argument ap is the va_list ap initialized by va_start(). Each call to va_arg() modifies ap so that the next call returns the next argument. The argument type is a type name specified so that the type of a pointer to an object that has the specified type can be obtained simply by adding a * to type.

The first use of the va_arg() macro after that of the va_start() macro returns the argument after last. Successive invocations return the values of the remaining arguments.

If there is no next argument, or if type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), random errors will occur.

If ap is passed to a function that uses va_arg(ap,type), then the value of ap is undefined after the return of that function.

Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function. After the call va_end(ap) the variable ap is undefined. Multiple traversals of the list, each bracketed by va_start() and va_end() are possible. va_end() may be a macro or a function.

The va_copy() macro copies the (previously initialized) variable argument list src to dest. The behavior is as if va_start() were applied to dest with the same last argument, followed by the same number of va_arg() invocations that was used to reach the current state of src.

An obvious implementation would have a va_list be a pointer to the stack frame of the variadic function. In such a setup (by far the most common) there seems nothing against an assignment

va_list aq = ap;

Unfortunately, there are also systems that make it an array of pointers (of length 1), and there one needs

va_list aq;
*aq = *ap;

Finally, on systems where arguments are passed in registers, it may be necessary for va_start() to allocate memory, store the arguments there, and also an indication of which argument is next, so that va_arg() can step through the list. Now va_end() can free the allocated memory again. To accommodate this situation, C99 adds a macro va_copy(), so that the above assignment can be replaced by

va_list aq;
va_copy(aq, ap);

Each invocation of va_copy() must be matched by a corresponding invocation of va_end() in the same function. Some systems that do not supply va_copy() have __va_copy instead, since that was the name used in the draft proposal.


Multithreading (see pthreads(7))
The va_start(), va_arg(), va_end(), and va_copy() macros are thread-safe.


The va_start(), va_arg(), and va_end() macros conform to C89. C99 defines the va_copy() macro.


These macros are not compatible with the historic macros they replace. A backward-compatible version can be found in the include file <varargs.h>.

The historic setup is:

#include <varargs.h>

va_list ap;

while (...) {
x = va_arg(ap, type);

On some systems, va_end contains a closing '}' matching a '{' in va_start, so that both macros must occur in the same function, and in a way that allows this.


Unlike the varargs macros, the stdarg macros do not permit programmers to code a function with no fixed arguments. This problem generates work mainly when converting varargs code to stdarg code, but it also creates difficulties for variadic functions that wish to pass all of their arguments on to a function that takes a va_list argument, such as vfprintf(3).


The function foo takes a string of format characters and prints out the argument associated with each format character based on the type.

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

foo(char *fmt, ...)
va_list ap;
int d;
char c, *s;

va_start(ap, fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
printf("string %s\n", s);
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
case 'c': /* char */
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);


This page is part of release 3.69 of the Linux man-pages project. A description of the project, information about reporting bugs, and the latest version of this page, can be found at−pages/.

More Linux Commands

netdevice(7) - Low level access to Linux network devices....
This man page describes the sockets interface which is used to configure network devices. Linux supports some standard ioctls to configure network devices. They

ber_bvecadd(3) - OpenLDAP LBER types and allocation function
The following are the basic types and structures defined for use with the Lightweight BER library. ber_int_t is a signed integer of at least 32 bits. It is comm

Tcl_UniCharIsGraph(3) - routines for classification of Tcl_U
All of the routines described examine Tcl_UniChars and return a boolean value. A non-zero return value means that the character does belong to the character cla

git-remote-testgit(1) - Example remote-helper (Man Page)....
This command is a simple remote-helper, that is used both as a testcase for the remote-helper functionality, and as an example to show remote-helper authors one

set_thread_area(2) - Set a Thread Local Storage (TLS) area
set_thread_area() sets an entry in the current threads thread-local storage (TLS) array. The TLS array entry set by set_thread_area() corresponds to the value o

snprintf(3) - formatted output conversion - Linux man page
The functions in the printf() family produce output according to a format as described below. The functions printf() and vprintf() write output to stdout, the s

elvtune(8) - I/O elevator tuner (Admin - Linux man page)....
elvtune allows to tune the I/O elevator per blockdevice queue. The tuning can be safely done at runtime. Tuning the elevator means being able to change disk per

perlhack(1) - How to hack on Perl - Linux manual page.......
This document explains how Perl development works. It includes details about the Perl 5 Porters email list, the Perl repository, the Perlbug bug tracker, patch

XtAppSetTypeConverter(3) - register resource converter......
XtSetTypeConverter registers the specified type converter and destructor in all application contexts created by the calling process, including any future applic

crond(8) - daemon to execute scheduled commands (Man Page)
Cron is started from /etc/rc.d/init.d or /etc/init.d when classical sysvinit scripts are used. In case systemd is enabled, then unit file is installed into /lib

XFree86-DGA(3) - Client library for the XFree86-DGA extensio
The XFree86-DGA extension is an X server extension for allowing client programs direct access to the video frame buffer. This is a brief description of the prog

is_notimeout(3ncurses) - curses window properties (ManPage)
This implementation provides functions which return properties set in the WINDOW structure, allowing it to be opaque if the symbol NCURSES_OPAQUE is defined: is

We can't live, work or learn in freedom unless the software we use is free.