The first call to setjmp causes the process state (stack, CPU registers, etc.) to be saved in the provided jmp_buf structure and, then, a value of 0 to be returned. A subsequent call to longjmp with the same jmp_buf structure causes the process to go "back in time" to the state stored in said structure. The way this is useful is that, when going back in time, we tweak the return value of the setjmp call so we can actually run a second (or third or more) path as if nothing had happened.
Let's see an example:
#include <setjmp.h>The example above shows the following when executed:
#include <stdio.h>
#include <stdlib.h>
static jmp_buf buf;
static void
myfunc(void)
{
printf("In the function.n");
... do some complex stuff ...
/* Go back in time: restore the execution context of setjmp
* but make the call return 1 instead of 0. */
longjmp(buf, 1);
printf("Not reached.n");
}
int
main(void) {
if (setjmp(buf) == 0) {
/* Try block. */
printf("Trying some function that may throw.n");
myfunc();
printf("Not reached.n");
} else {
/* Catch block. */
printf("Exception caught.n");
}
return EXIT_SUCCESS;
}
Trying some function that may throw.So, what happened above? The code starts by calling setjmp to record the execution state and the call returns 0, which causes the first part of the conditional to run. You can think of this clause as the "try" part of an exception-based code. At some point during the execution of myfunc, an error is detected and is "thrown" by a call to longjmp and a value of 1. This causes the process to go back to the execution of setjmp but this time the call returns 1, which causes the second part of the conditional to run. You can think of this second clause as the "catch" part of an exception-based code.
In the function.
Exception caught.
It is still unclear to me what the "execution context" stored in jmp_buf is: the documentation does not explain what kind of resources are correctly unwinded when the call to longjmp is made... which makes me wary of using this technique for exception-like handling purposes. Oh, and this is even less clear in the context of C++ code and, e.g. calls to destructors. Would be nice to expand the description of these APIs in the manual pages.