For a discussion of argument passing issues, see §3.7.1.
These macros,
modeled after the UNIX <varargs.h>
macros,
have been added to enable the portable implementation in C
of library functions such as printf
and scanf
(see §4.9.6).
Such implementation could otherwise be difficult,
considering newer machines that may pass arguments in machine
registers rather than using the more traditional stack-oriented methods.
The definitions of these macros in the Standard differ from their forebears: they have been extended to support argument lists that have a fixed set of arguments preceding the variable list.
va_start
and va_arg
must exist as macros,
since va_start
uses an argument that is passed by name and
va_arg
uses an argument which is the name of a data type.
Using #undef
on these names leads to undefined behavior.
The va_list
type is not necessarily assignable.
However, a function can pass a pointer to its initialized argument
list object, as noted below.
va_start
macro
va_start
must be called within the body of the function whose argument
list is to be traversed.
That function can then pass a pointer to its va_list
object ap
to other functions to do the actual traversal.
(It can, of course, traverse the list itself.)
The parmN
argument to va_start
is an aid to writing
conforming ANSI C code for existing C implementations.
Many implementations can use the second parameter within the structure
of existing C language constructs to derive the address of the first
variable argument.
(Declaring parmN
to be of storage class register
would interfere
with use of these constructs;
hence the effect of such a declaration is undefined behavior.
Other restrictions on the type of parmN
are imposed for the
same reason.)
New implementations may choose to use hidden machinery that ignores the
second argument to va_start
, possibly even hiding a function call
inside the macro.
Multiple va_list
variables can be in use simulaneously
in the same function;
each requires its own calls to va_start
and va_end
.
va_arg
macro
Changing an arbitrary
type name
into a type name which is a pointer to that type
could require sophisticated rewriting.
To allow the implementation of va_arg
as a macro,
va_arg
need only correctly handle those type names that can
be transformed into the appropriate pointer type by appending a *
,
which handles most simple cases.
(Typedefs can be defined to reduce more complicated
types to a tractable form.)
When using these macros
it is important to remember that the type of an argument in a variable
argument list will never be an integer type smaller than int
,
nor will it ever be float
.
(See §3.5.4.3.)
va_arg
can only be used to access the value of an argument,
not to obtain its address.
va_end
macro
va_end
must also be called from within the body of the function having
the variable argument list.
In many implementations, this is a do-nothing operation;
but those implementations that need it probably need it badly.