Reputation: 91017
I have a function which looks like
void demo_function_v(const char * mask, va_list ap)
{
for (; *mask; mask++) {
// get one or more args from ap, depending on *mask
}
}
This runs on a AVR system which has different access techniques for the flash memory. In order to duplicate this function, I'd like to extract the main part of it:
void demo_function_1char(char mask, va_list ap)
{
// get one or more args from ap, depending on mask
}
void demo_function_v(const char * mask, va_list ap)
{
for (; *mask; mask++) {
demo_function_1char(*mask, ap)
}
}
Alas, this is not guaranteed to work, as
The object
ap
may be passed as an argument to another function; if that function invokes theva_arg
macro with parameterap
, the value ofap
in the calling function is indeterminate.
And this is true - on x86, it doesn't work, on x64, it does. If it works on AVR, I'll be able to test tomorrow. But I'd rather not rely on this if it is described as "indeterminate" (which is supposedly a kind of UB).
Thus, I'd like to go another track:
void demo_function_1char(char mask, va_list * pap)
{
// get one or more args from *pap, depending on mask
}
void demo_function_v(const char * mask, va_list ap)
{
for (; *mask; mask++) {
demo_function_1char(*mask, &ap)
}
}
Is this supposed to work, or will I shoot my foot this way as well?
Upvotes: 1
Views: 769
Reputation: 340168
The C99 standard has the following footnote clarifying this:
It is permitted to create a pointer to a va_list and pass that pointer to another function, in which case the original function may make further use of the original list after the other function returns.
I believe that behavior was also the intent in C90 even if the standard didn't note it. The C90 rationale document does have this to say:
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
must be called within the body of the function whose argument list is to be traversed. That function can then pass a pointer to itsva_list
objectap
to other functions to do the actual traversal. (It can, of course, traverse the list itself.)
Making it pretty clear, I think, that accessing the va_list
object through a pointer acts as you'd expect (that the va_list
state is being maintained in the object instance that the address was taken from), even if it doesn't explicitly state that the original va_list
object will pick up where the pointer usage left off. For it to not work this way, pointers to va_list
objects would have to behave differently than pointers to other C objects.
Upvotes: 4