在此Q& A中,确定您应始终致电va_end()
:
What exactly is va_end for? Is it always necessary to call it?
但是,如果在到达va_end之前有一段代码是longjmp? va_end的部分是否有任何承诺可以接受?或者概念上它可能(例如)在va_start()
中进行内存分配会泄露,而不仅仅是使用堆栈技巧?
答案 0 :(得分:8)
C99 rationale明确指出va_start
可能会分配最终由va_end
释放的内存,这正是您在问题中所猜测的内容:
7.15.1.2
va_copy
宏[...]
30一种更简单的方法是复制用于表示参数处理的
va_list
对象。但是,没有安全的方法 在C89中执行此操作,因为该对象可能包含指向由va_start
宏分配并由va_end
宏销毁的内存的指针。
新的va_copy
宏提供了这种安全机制。[...]
所以是的,您需要在va_end
之前调用longjmp
。至少你会在这种实现上发生内存泄漏。
据说Pyramid OSx有一个实现,其中内存分配由va_start
执行。函数参数在寄存器中传递。即使对于可变函数也是如此。它可能早于ANSI C发明的函数原型,这意味着调用者不知道它是否处理可变函数。 va_start
分配了内存,可能是以va_arg
可以轻松访问它的方式存储函数参数值。 va_end
释放了已分配的内存。
va_start
和va_end
的实现实际上需要在语法上匹配va_start
和va_end
,因为它是使用不平衡大括号的,因此ANSI C已经禁止该实现,但是同样的原则可以在匹配括号的同时工作。
我可以找到关于这个实现的非常少的具体信息,它在80年代末,90年代早期的Usenet上只是点点滴滴。我找到的一点点可能是不完整的,甚至是完全错误的。更多细节非常受欢迎,尤其是那些自己使用此实现的人。