我知道人们总是说不要使用longjmp
,这是邪恶的,这很危险。
但我认为它可以用于退出深度递归/嵌套函数调用。
单个longjmp
比if(returnVal != SUCCESS) return returnVal;
等重复检查和返回更快吗?
至于安全性,只要动态释放动态内存和其他资源,就不会出现问题,对吗?
到目前为止似乎使用longjmp
并不困难,它甚至使我的代码更加严格。我很想使用它。
(恕我直言,在很多情况下,首先在深度递归中没有分配动态内存/资源。深度函数调用似乎更常见于数据解析/操作/验证。动态分配通常在更高级别发生,然后再调用setjmp
出现的函数。)
答案 0 :(得分:4)
setjmp
和longjmp
可被视为穷人的exception机制。 BTW,Ocaml例外与setjmp
一样快,但语义更清晰。
当然,longjmp
比在中间函数中重复返回错误代码要快得多,因为它会弹出一个可能很重要的call stack部分。
(我暗中关注Linux)
只要没有在它们之间分配资源,它们就是有效且有用的,包括:
malloc
)fopen
- ing FILE*
句柄主要问题是非leaking resources的属性是全局整个程序属性(或者至少是所有可能在{之间调用的函数的全局属性) {1}}和setjmp
),因此它禁止modular software development:任何其他同事必须在longjmp
和setjmp
之间的任何功能中改进某些代码时必须注意这一点限制并遵循该规则。
因此,如果您非常清楚地使用 longjmp
文档。
顺便说一句,如果您仅关心setjmp
,系统地使用 Boehm's保守garbage collector会有很大帮助;您将在任何地方使用malloc
代替GC_malloc
,而您不会关心malloc
,实际上这就足够了;然后,您可以毫无顾虑地使用free
(因为您可以在setjmp
和GC_malloc
之间拨打setjmp
。
(请注意,垃圾收集器的概念和术语与异常处理和longjmp
密切相关,但很多人对它们了解不够。阅读Garbage Collection Handbook应该是值得的)功能
另请阅读RAII并了解C++11例外情况(及其与destructors的关系)。了解continuations和CPS。
阅读setjmp(3),longjmp(3)(以及约setjmp
,sigsetjmp
和setcontext(3))并注意编译器必须了解{{ 1}}
答案 1 :(得分:2)
您应该注意,在某些上下文中调用setjmp并不能保证安全(例如,您无法移植存储setjmp的返回值)。
另外,如果你想在调用setjmp后访问局部变量,在同一个函数中,可能已经改变了,你应该将变量标记为volatile。
使用setjmp和longjmp也很有用,因为如果递归导致堆栈溢出,您可以使用信号处理程序中的longjmp进行恢复(不要忘记设置备用堆栈)并返回错误。如果你想这样做,你应该考虑使用sigsetjmp和siglongjmp来保存信号处理。