20

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

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

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

更好的是,是否已经存在一些用于错误/异常处理的 C 库?

4

6 回答 6

14

如果您担心资源清理,您必须认真考虑 longjmp() 和 setjmp() 是否是一个好主意。

如果您设计的资源分配系统实际上可以准确地清理,那么它是可以的 - 但是如果您的代码使用的标准库自己分配的资源必须被发布。它需要特别小心,并且由于它不是完全可靠的,因此它不适合可能需要多次使用 setjmp()/longjmp() 调用(它们会泄漏、扩展并最终导致问题)。

于 2009-05-04T17:44:23.820 回答
13

看看这个例子/教程:
http ://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html

于 2009-05-04T15:12:11.377 回答
5

我只发现了一种用途setjmp()/longjmp(),它与错误处理无关。

真的没有必要为此使用它,因为它总是可以被重构为更容易理解的东西。的使用setjmp()/longjmp()非常相似goto,因为它很容易被滥用。通常,任何使您的代码可读性降低的事情都是一个坏主意。请注意,我并不是说它们天生就不好,只是说它们比替代品更容易导致糟糕的代码。

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

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

于 2009-05-04T12:32:58.780 回答
5

Symbian 实现了它的Leave机制,longjmp()这可以很好地完成您需要做的所有事情。

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

Symbian 有它可以跳出的“陷阱线束”;这些可以嵌套。

(Symbian 最近根据 C++ 异常重新实现了它,但接口保持不变)。

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

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

使用 C++ 作为更好的 C,您只采用异常和 RAII,将是一个很好的途径,应该使用longjmp()异常仿真对您很有吸引力。

于 2009-05-04T12:35:42.970 回答
0

到目前为止,异常是一种更好的通用机制,但在 C 过去的黑暗时期,我编写了一个包含命令 shell 的处理器模拟器。用于设置jmp/longjmp 以进行中断处理的shell(即,处理器正在运行并且用户点击break/ctrl-c,代码将SIGINT 和longjmps 捕获回shell)。

于 2009-05-04T12:54:06.403 回答
0

我已经使用setjmp/longjmp相当整洁地从回调中逃脱,而无需通过各种其他库级别进行协商。

这种情况(如果我没记错的话)是 yacc 生成的解析器中的代码可以检测到(非语法)问题,并希望放弃解析但将合理有用的错误报告返回给另一端的调用者所有 yacc 生成的代码。另一个例子是在从 Expat 解析器调用的回调中。在每种情况下,都有其他方法可以做到这一点,但它们似乎比简单地以这种方式纾困更麻烦和晦涩。

但是,正如其他答案所指出的那样,有必要小心清理,并且非常周到地确保longjmp代码只能在setjmp.

在多线程编程的上下文中这样做?我敢肯定这不是不可能的,但是哦:现在就拿出你家装的阿司匹林吧。setjmp将/longjmp对尽可能靠近可能是明智之举。只要匹配setjmp/longjmp对在同一个线程中,我希望你会没事,但是......要小心。

于 2014-08-12T15:37:23.480 回答