va_end
- Macro to resetarg_ptr
.
After accessing a variable argument list, the arg_ptr
pointer is usually reset with va_end()
. I understand that it is required if you want to re-iterate the list, but is it really needed if you aren't going to? Is it just good practice, like the rule "always have a default:
in your switch
"?
You can always call va_start and va_end as much as you want. @MattMcNabb On x86-64 va_list maintains the state of traversal. On x86 it does not.
The C library macro void va_end(va_list ap) allows a function with variable arguments which used the va_start macro to return. If va_end is not called before returning from the function, the result is undefined.
va_list is a complete object type suitable for holding the information needed by the macros va_start, va_copy, va_arg, and va_end. If a va_list instance is created, passed to another function, and used via va_arg in that function, then any subsequent use in the calling function should be preceded by a call to va_end.
va_copy() The va_copy() macro copies the (previously initialized) variable argument list src to dest. The behavior is as if va_start() were applied to dest with the same last argument, followed by the same number of va_arg() invocations that was used to reach the current state of src.
va_end
is used to do cleanup. You don't want to smash the stack, do you?
From man va_start
:
va_end()
Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function. After the call va_end(ap) the variable ap is undefined. Multiple traversals of the list, each bracketed by va_start() and va_end() are possible. va_end() may be a macro or a function.
Note the presence of the word must.
The stack could become corrupted because you don't know what va_start()
is doing. The va_*
macros are meant to be treated as black boxes. Every compiler on every platform can do whatever it wants there. It may do nothing, or it may do a lot.
Some ABIs pass the first few args in registers, and the remainder on the stack. A va_arg()
there may be more complicated. You can look up how a given implementation does varargs, which may be interesting, but in writing portable code you should treat them as opaque operations.
On Linux x86-64 only one traversal can be done over a va_list
variable. To do more traversals it has to be copied using va_copy
first. man va_copy
explains the details:
va_copy()
An obvious implementation would have a va_list be a pointer to the stack frame of the variadic function. In such a setup (by far the most common) there seems nothing against an assignment
va_list aq = ap;
Unfortunately, there are also systems that make it an array of pointers (of length 1), and there one needs
va_list aq; *aq = *ap;
Finally, on systems where arguments are passed in registers, it may be necessary for va_start() to allocate memory, store the arguments there, and also an indication of which argument is next, so that va_arg() can step through the list. Now va_end() can free the allocated memory again. To accommodate this situation, C99 adds a macro va_copy(), so that the above assignment can be replaced by
va_list aq; va_copy(aq, ap); ... va_end(aq);
Each invocation of va_copy() must be matched by a corresponding invoca‐ tion of va_end() in the same function. Some systems that do not supply va_copy() have __va_copy instead, since that was the name used in the draft proposal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With