在本Q&A中,您应该始终调用va_end()
:
va_end到底是干什么用的?总是需要调用它吗?
但是如果一段代码在到达va_end之前长了jmp's呢?va_end方面是否有任何承诺,它将是好的?或者从概念上讲,它(例如)在va_start()
中做内存分配,这将被泄露,而不是仅仅使用堆栈技巧?
C99的基本原理明确指出,va_start
可能分配内存,最终由va_end
释放,正是你在你的问题中猜测的:
7.15.1.2va_copy
宏[…]一个更简单的方法是复制用于表示参数处理的
va_list
对象。然而,没有安全的方法在C89中这样做是因为对象可能包含指向由va_start
宏分配并由va_end
宏销毁的内存的指针。
新的va_copy
宏提供了这种安全机制。[…]
所以,是的,您需要在longjmp
之前调用va_end
。在这样的实现中,至少会出现内存泄漏。
假设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上的一些零零碎碎的东西。我所发现的那一点可能是不完整的,甚至是完全错误的。更多的细节是非常受欢迎的,特别是那些自己使用这个实现的人。
如果您正在使用存储在全局变量中的jmp_buff
(通常的模式),则应该安全地复制它并使用setjmp
,以便longjmp
将转到您的代码而不是外部调用者;在longjmp
的情况下,你的代码可以使用缓冲区的存储副本调用va_end
和longjmp
;如果您的代码正常退出,则需要在返回之前恢复全局缓冲区。