Hacker News new | past | comments | ask | show | jobs | submit login

"setjmp" and "longjmp" are the mechanism for implementing exceptions in C, i.e. they are just another form of writing "catch" and "throw".

The implementation of exceptions, i.e. of jumps over multiple levels of nested functions and blocks, is much simpler in C than in C++, because there are no destructors that must be called when unwinding the stack, so it is enough to restore the CPU registers to the values correct for the program point where the exception must be caught.

This is needed because at the point where the exception is thrown it is not known whether any of the nested functions that must be skipped has modified any of the registers that a function is expected to preserve and where the original values of the registers have been saved.

Any kind of exceptions can be easily misused, which is why it is recommended to be careful with the use of "setjmp" and "longjmp", but they are not more harmful than the use of exceptions in any other language.

The only additional problem of C is that since there are no implicitly called destructors, like in C++ and similar languages, in C the programmer must do what the compiler would do in C++.

This means that if the nested functions that are skipped by a "longjmp" have allocated heap memory, opened files or sockets etc., such resources must be freed in the exception handler marked by a "setjmp".

Therefore the C programmer must keep track of the resources that might have been allocated in the nested functions, e.g. by recording the allocations in some global table.




As well as being harder to work with correctly setjmp and longjmp are often a lot slower than other exception handling systems as you are paying the full cost of saving lots of register state even if an exception isn’t thrown. I’ve seen this cause serious performance issues on Windows on x86-64 in the past.

It also doesn’t really compose well, so if library A is using it for exceptions and library B is doing something else clever then it’s hard to coordinate those two uses.


Can you elaborate? Isn't the c++ exception system built on top of setjmp/longjmp?

For setjmp to have a measurable performance impact, you have to be calling it an awful lot. It is just a handful of mov instructions without dependencies.


> Isn't the c++ exception system built on top of setjmp/longjmp?

It is not. The dominant C++ exception system is based on "zero-cost exception handling", which refers to the fact that you do not call any extra code (like setjmp) until an exception is to be thrown. All of that logic is instead encapsulated in tables of exception-handling data and sophisticated unwind routines that look up those tables to figure out where to transfer control-flow to.

> For setjmp to have a measurable performance impact, you have to be calling it an awful lot.

If you built the C++ exception system on top of setjmp/longjmp, you would have to call setjmp on every instance that begins a try block. This includes implicit try blocks generated for every object that has a nontrivial destructor (which must be called if you unwind through the block). So yeah, you would be calling it an awful lot...


There are C++ exception implementation's based on setjmp/longjmp though, e.g. MinGW's sjlj configuration.


Right, I should have known, libunwind is a basic requirement for supporting a C++ runtime on a target.


Depending on the ABI it’s saving a lot of registers, and it is very easy to end up calling it a lot if you cannot guarantee the code that may be called by functions you call and you need to do any cleanup.

C++ and other languages tend to make the fast path of no exception extremely fast and store additional data about functions that allow for stack unwinding when an exception is thrown.


None of the popular C++ vendors implement C++ exceptions using setjmp/longjmp on any of the more (and very few of the less) common targets. Maintaining C++ language runtimes is a part of my day job and I am thankful they don't.


> "setjmp" and "longjmp" are the mechanism for implementing exceptions in C

Correct, but reductive.

They can be used for many other things.


The more general POV is that "setjmp" defines a continuation and "longjmp" invokes it.

While the most frequent use of explicit continuations is for implementing exceptions, you are right that there are many other programming techniques based on explicit continuations (for instance coroutines).


I'm now wondering if anyone has written an actual continuation library in C (ie saving and restoring the whole stack). Is it possible?


yes and yes.


Coroutines are one good example.


> They can be used for many other things.

The underlying primitive offers even more flexibility, but exceptions (in the sense of programming languages) can also be used for many other things than exceptions (in the sense of natural language, to handle exceptional cases).


>"... but exceptions (in the sense of programming languages) can also be used for many other things than exceptions ..."

Can you elaborate? What are the other ways exceptions are used when not used to handle exceptional situations?




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: