== Why I'm wrong about what sort of APIs C's stdargs allows One of the things that blogging gives me is the chance to be very wrong in public. [[Yesterday CStdargImpossibleApi]], I claimed that C's stdargs didn't let you peel some arguments off the front of a ((va_list)) and then pass the shortened list to another function, such as _vprintf()_. Well, no, and now I'll tell you why I'm wrong. I'm clearly wrong in practice on x86 Unix machines with gcc, as a simple test program easily demonstrated once a commentator raised doubts and I bothered to check. But I also believe that I'm wrong even in theory and that this sort of manipulation of ((va_list)) likely has to be supported by any spec-compliant C compiler. While this is not spelled out directly in the documentation I've read, I think that it arises by implication from things like the [[Single Unix Specification stdarg page http://www.opengroup.org/onlinepubs/9699919799/basedefs/stdarg.h.html]]. (A disclaimer: I haven't read the ANSI/ISO C standard, so this may be clearly spelled out there.) First, assume that you can write a standards-compliant C function that accepts a ((va_list)) argument and works directly with it, an equivalent of _vprintf()_ or the like. The only way this function has to extract arguments from the ((va_list)) is with _[[va_arg()|]]_, which it's allowed to use. _[[va_arg()|]]_ requires that you first call _[[va_start()|]]_. However, our ((va_list)) receiving function cannot call _[[va_start()|]]_ itself; _[[va_start()|]]_ must be invoked with the identifier of the rightmost parameter before the _..._ *in the varargs function definition*, which exists only in the context of the caller of our function. So the caller must call _[[va_start()|]]_ before invoking our function, and in fact is the only function that can. And once you call _[[va_start()|]]_, the behavior of _[[va_arg()|]]_ is quite well specified and contains no mention of the ((va_list)) being reset when you call a function; each time you call _[[va_arg()|]]_, you advance the ((va_list)) to the next parameter (until you run out). Hence I believe that the C standard almost certainly requires that if you call _[[va_arg()|]]_ and then pass the ((va_list)) to another function, that function sees the ((va_list)) just as you would and gets the same results from calling _[[va_arg()|]]_ that you would. Peeling arguments off your ((va_list)) and then calling a v* function with the remainder is perfectly spec-compliant behavior. This still leaves the C stdarg stuff moderately constrained, but it's less constrained than I thought. === Sidebar: Why you have to reset ((va_list)) after function calls ((va_list)) is an opaque type that is effectively an iterator, and implementations are free to make it have internal state that is manipulated by _[[va_arg()|]]_. Thus, when you call a function and pass it a ((va_list)), that function may manipulate the internal state of your iterator and leave it in some random state, or simply at the end of the varargs parameters. So you have to reset it in order to be able to use it again yourself. (This idea is achingly familiar to anyone who has ever passed iterators around in Python.)