va_list argument actually is not a va_list
va_list
is permitted by the standard to be an array, and often it is.
That means va_list
in a function argument gets adjusted to a pointer to whatever va_list
's internal first element is.
The weird rule (7.16p3) regarding how va_list
gets passed basically accommodates the possibility that va_list
might be of an array type or of a regular type.
I personally wrap va_list
in a struct
so I don't have to deal with this.
When you then pass pointers to such a struct va_list_wrapper
, it's basically as if you passed pointers to va_list
, and then footnote 253 applies which gives you the permission to have both a callee and a caller manipulate the same va_list
via such a pointer.
(The same thing applies to jmp_buf
and sigjmp_buf
from setjmp.h
. In general, this type of array to pointer adjustment is one of the reasons why array-typed typedef
s are best avoided. It just creates confusion, IMO.)
Another solution (C11+ only):
_Generic(vl, va_list: &vl, default: (va_list *)vl)
Explanation: if vl
has type va_list
, then va_list
isn't an array type and just taking the address is fine to get a va_list *
pointing to it. Otherwise, it must have array type, and then you're permitted to cast a pointer to the first element of the array (whatever type that is) to a pointer to the array.