Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What exactly is va_end for? Is it always necessary to call it?

va_end - Macro to reset arg_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"?

like image 714
Yarik Avatar asked Feb 25 '09 18:02

Yarik


People also ask

Do you need to call Va_end?

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.

What is the purpose of Va_end?

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.

What is a Va_list?

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.

What is Va_copy?

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.


2 Answers

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.

like image 172
greyfade Avatar answered Sep 28 '22 04:09

greyfade


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.

like image 44
Maxim Egorushkin Avatar answered Sep 28 '22 04:09

Maxim Egorushkin