安全使用“setjmp”和“longjmp”

csh*_*shu 6 c performance memory-leaks setjmp

我知道人们总是说不要使用longjmp,它是邪恶的,它是危险的。

但我认为它对于退出深度递归/嵌套函数调用很有用。

是不是一次下单longjmp比多次重复检查和退货要快一些if(returnVal != SUCCESS) return returnVal;

至于安全性,只要动态内存等资源释放得当,应该不会有问题吧?

到目前为止,使用似乎longjmp并不困难,甚至使我的代码更简洁。我很想经常使用它。

(恕我直言,在许多情况下,首先在深度递归中没有分配动态内存/资源。深度函数调用对于数据解析/操作/验证来说似乎更常见。动态分配通常发生在更高级别,然后调用函数,其中setjmp出现。)

Bas*_*tch 7

setjmp可以longjmp看作是穷人的例外机制。顺便说一句,Ocaml异常速度一样快setjmp,但语义更清晰。

当然, alongjmp比在中间函数中重复返回错误代码要快得多,因为它会弹出一个可能重要的调用堆栈部分。

(我隐含地关注Linux)

只要它们之间没有分配资源,它们就是有效且有用的,包括:

  • 堆内存 ( malloc)
  • fopen-ingFILE*手柄
  • 打开操作系统文件描述符(例如套接字)
  • 其他操作系统资源,例如计时器或信号处理程序
  • 获取由某些服务器管理的外部资源,例如 X11 windows(因此使用任何小部件工具包,如 GTK),或数据库句柄或连接...
  • ETC...

主要问题是,不泄漏资源的属性是全局的整个程序属性(或者至少对于所有可能在setjmp和之间调用的函数来说是全局的longjmp),因此它禁止模块化软件开发:任何其他同事都必须改进任何函数中的某些代码之间setjmp并且longjmp必须意识到该限制并遵循该纪律。

因此,如果您使用 setjmp文档就非常清楚。

顺便说一句,如果你关心,系统地malloc使用Boehm 的保守垃圾收集器会有很大帮助;您将使用而不是到处使用并且您不会关心,实际上这就足够了;那么你就可以不用担心地使用(因为你可以在和之间调用)。 GC_mallocmallocfreesetjmpGC_mallocsetjmplongjmp

(请注意,垃圾收集器周围的概念和术语与异常处理和异常相关setjmp,但很多人对它们了解不够。阅读垃圾收集手册应该是值得的)

另请阅读RAII并了解C++11异常(及其与析构函数的关系)。了解一些有关延续CPS 的知识。

阅读setjmp(3)longjmp(3)(以及有关sigsetjmpsiglongjmpsetcontext(3))并注意编译器必须了解setjmp