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_list
variables进行一次遍历。 要进行更多的遍历,必须首先使用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.