va_end究竟是什么?是否总是需要打电话给它?

时间:2009-02-25 18:01:16

标签: c++ c variadic-functions

  

va_end - 重置arg_ptr的宏。

访问变量参数列表后,arg_ptr指针通常会被va_end()重置。我知道如果你想重新迭代这个列表是必需的,但如果你不去,它是否真的需要?这只是一种很好的做法,就像规则“default:中总是有switch一样吗?”

3 个答案:

答案 0 :(得分:45)

va_end用于进行清理。你不想粉碎堆栈,是吗?

来自man va_start

  

va_end用来()

     

每次调用va_start()都必须与同一函数中相应的va_end()调用相匹配。在调用va_end(ap)之后,变量ap未定义。列表的多次遍历,每个遍历由va_start()和va_end()括起来都是可能的。 va_end()可以是宏或函数。

请注意一词必须

堆栈可能会损坏,因为您不知道va_start()正在做什么va_*宏意味着被视为黑盒子。每个平台上的每个编译器都可以做任何想做的事情。它可能什么都不做,或者可能做很多事情。

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

答案 1 :(得分:13)

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

  

va_copy()

     

一个明显的实现将使va_list成为指向的指针      可变功能的堆栈框架。在这样的设置(迄今为止最多      共同的)似乎没有任何反对任务

   va_list aq = ap;
     

不幸的是,还有一些系统使它成为一个指针数组      (长度为1),并且需要

   va_list aq;
   *aq = *ap;
     

最后,在寄存器中传递参数的系统上,它可能是      va_start()分配内存,在那里存储参数,      并且还指示下一个参数,以便va_arg()可以      逐步完成清单。现在va_end()可以释放分配的内存      再次。为了适应这种情况,C99添加了一个宏va_copy(),所以      上述作业可以用

代替
   va_list aq;
   va_copy(aq, ap);
   ...
   va_end(aq);
     

每次调用va_copy()都必须与相应的invoca-匹配      在同一个函数中的va_end()。一些不供应的系统      va_copy()改为__va_copy,因为那是在中使用的名称      提案草案。

答案 2 :(得分:12)

在常见的“在堆栈上传递的参数”实现中,我相信va_end()通常没有/ empty / null。但是,在传统方案较少的平台上,这是必要的。包含它以保持平台中立是一种“良好做法”。