va_list argument actually is not a va_list
va_list is permitted by the standard to be an array, and often it is.
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
setjmp.h. In general, this type of array to pointer adjustment is one of the reasons why array-typed
typedefs are best avoided. It just creates confusion, IMO.)
Another solution (C11+ only):
_Generic(vl, va_list: &vl, default: (va_list *)vl)
vl has type
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.