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

前端 未结 3 1168
陌清茗
陌清茗 2020-12-08 04:10

va_end - Macro to reset arg_ptr.

After accessing a variable argument list, the arg_ptr pointer is

相关标签:
3条回答
  • 2020-12-08 04:13

    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.

    0 讨论(0)
  • 2020-12-08 04:33

    In the common "parameters passed on the stack" implementation, I believe va_end() is usually nothing/empty/null. However, on platforms which have less traditional schemes, it becomes necessary. It's a "good practice" to include it to remain platform neutral.

    0 讨论(0)
  • 2020-12-08 04:34

    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.

    0 讨论(0)
提交回复
热议问题