使用longjmp / setjmp进行C错误处理有哪些“好”的方法?

时间:2009-05-04 12:23:14

标签: c error-handling longjmp setjmp

我必须将C用于一个项目,我正在考虑使用longjmp/setjmp进行错误处理,因为我认为在一个中心位置处理错误要比返回代码容易得多。如果有关于如何做到这一点的一些线索,我将不胜感激。

如果发生任何此类错误,我特别关注正确完成资源清理。

另外,我如何处理导致多线程程序使用它们的错误?

更好的是,是否有一些C库已经存在以进行错误/异常处理?

6 个答案:

答案 0 :(得分:14)

如果你担心资源清理,你必须认真地想知道longjmp()和setjmp()是否是一个好主意。

如果您设计资源分配系统以便实际上可以准确地进行清理,那么就可以了 - 但这种设计往往很棘手,而且如果事实上您的代码自己使用的标准库分配的话通常是不完整的必须释放的资源。它需要特别小心,并且因为它不是完全可靠的,所以它不适合长时间运行的系统,它们可能需要经历多次使用setjmp()/ longjmp()调用(它们会泄漏,扩展并最终导致问题)。

答案 1 :(得分:12)

答案 2 :(得分:5)

我只发现一个用于setjmp()/longjmp(),而且与错误处理没有关系。

确实没有必要使用它,因为它总是可以重构为更容易理解的东西。使用setjmp()/longjmp()goto非常相似,因为它很容易被滥用。任何使你的代码可读性降低的东西一般都是个坏主意。请注意,我并不是说它们本身就很糟糕,只是因为它们比其他选择更容易导致代码错误。

FWIW,他们非常宝贵的一个地方是我在行业早期所做的一个项目(MS-DOS 6时间框架)。我设法使用Turbo C组建了一个合作多线程库,它在yield()函数中使用这些函数来切换任务。

我很确定我从那时起就没有碰过它们(或者有必要)。

答案 3 :(得分:5)

Symbian在Leave方面实施了longjmp()机制,这可以很好地了解您需要做的所有事情。

Symbian有一个全球性的“清理堆栈”,如果发生跳转,你可以推送和弹出你想要清理的东西。这是C ++编译器在抛出C ++异常时执行的自动堆栈展开的手动替代方法。

Symbian已经'陷阱'会跳出来;这些可以嵌套。

(Symbian最近在C ++异常方面重新实现了它,但界面保持不变)。

总之,我认为正确的C ++异常不太容易编码错误,并且比滚动自己的C等价物要快得多。

(例如,现代C ++编译器非常擅长“零开销”异常,例如; longjmp()必须存储所有寄存器的状态,即使以后不进行跳转,所以从根本上说永远不会像例外一样快。)

使用C ++作为更好的C,只使用异常和RAII,如果使用longjmp()异常仿真对你很有吸引力,那么这将是一个很好的途径。

答案 4 :(得分:0)

异常是一个更好的通用机制,但在C过去的黑暗时期,我写了一个包含命令shell的处理器模拟器。用于setjmp / longjmp的shell用于中断处理(即处理器正在运行,用户命中break / ctrl-c,代码将SIGINT和longjmps捕获回shell)。

答案 5 :(得分:0)

我已经合理地使用setjmp / longjmp来逃避回调,而无需通过各种其他图书馆级别进行协商。

那种情况(如果我没记错的话)是yacc生成的解析器中的代码可以检测到(非语法)问题,并且想要放弃解析但是将一个合理有用的错误报告返回给调用者所有yacc生成的代码的另一面。另一个例子是在一个从Expat解析器调用的回调中。在每种情况下,还有其他方法可以做到这一点,但它们似乎比以这种方式拯救更加麻烦和模糊。

正如其他答案所指出的那样,有必要小心清理,并且非常考虑确保longjmp代码只能在区域范围内动态调用受setjmp保护。

在多线程编程的上下文中执行此操作?我确定这并非不可能,但是哦:现在就拿出你的家庭装阿司匹林。将setjmp / longjmp对尽可能紧密地保持在一起可能是明智之举。只要匹配的setjmp / longjmp对在同一个帖子中,我希望你没问题,但是......要小心。