va_end到底是什么? 是否总是需要调用它?

va_end – macros来重置arg_ptr

访问variables参数列表后, arg_ptr指针通常会用va_end()重置。 我明白,如果你想重新列表的话,这是必须的,但如果你不打算,这真的是需要的吗? 这只是一个很好的习惯,就像规则“总是有一个default:在你的switch ”?

va_end被用来做清理。 你不想粉碎堆,你呢?

man va_start

va_end用来()

va_start()的每个调用都必须在同一个函数中通过相应的va_end()调用进行匹配。 在调用va_end(ap)之后,variablesap是未定义的。 列表中的多次遍历,每个遍历va_start()和va_end()都是可能的。 va_end()可能是一个macros或者一个函数。

注意必须存在这个词。

堆栈可能会被破坏,因为你不知道va_start()在做什么va_*macros是为了被视为黑盒子。 每个平台上的每个编译器都可以做任何想要的。 它可能什么也不做,也可能做很多。

一些ABI传递寄存器中的前几个参数,其余的则放在堆栈中。 一个va_arg()可能会更复杂。 您可以查看给定的实现如何进行可变参数,这可能是有趣的,但是在编写可移植代码时,您应该将它们视为不透明的操作。

在通用的“堆栈传递参数”实现中,我相信va_end()通常是nothing / empty / null。 但是,在传统scheme较less的平台上,这是必要的。 将其纳入平台保持中立是一种“良好做法”。

在Linux x86-64上,只能通过va_listvariables进行一次遍历。 要进行更多的遍历,必须首先使用va_copy进行复制。 man va_copy解释详细信息:

 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.