Let’s recall briefly how the standard, C language, non–local exits mechanism works; for the full documentation refer to the C Library. (libc)Non-Local Exits.
To use setjmp() and longjmp() we write chunks of code like the following:
#define JMP_ERROR_CODE 1
jmp_buf here;
if (setjmp(here))
{
handle_the_error();
}
else
{
do_something();
if (an_error_occurred()) {
longjmp(here, JMP_ERROR_CODE);
}
do_something_else();
}
this is what happens:
setjmp() is invoked: it saves the current “location” in here, then it returns
zero.
longjmp() is not applied to here, nothing strange happens and the execution flow goes
on as usual.
longjmp() is applied to here: the execution jumps back to the call to setjmp()
with JMP_ERROR_CODE as return value.
This mechanism allows us to separate the exception handling code from the main code. By using
here as argument to nested function calls: we can perform non–local exits across functions;
something that is not possible with goto statements.
As always, care must be taken when the body allocates asynchronous resources. For each resource: the exception handler must detect if the allocation took place and execute release code. For example:
jmp_buf here;
volatile void * P = NULL;
if (setjmp(here))
{
if (P)
free(P);
}
else
{
...
P = malloc(4096);
...
}
Let’s see some logic example; we will assume the following preamble:
#include <assert.h> #include <stdlib.h> #include <setjmp.h> #define JUMP_TO_ERROR 2
In the following code no jump is performed; we just call setjmp() once and never call
longjmp():
jmp_buf L;
int flag = 0, code;
code = setjmp(L);
if (code) {
flag = 2;
} else {
flag = 1;
}
assert(0 == code);
assert(1 == flag);
In the following code we perform a jump and handle the logic with an if statement:
jmp_buf L;
int flag = 0, code;
code = setjmp(L);
if (JUMP_TO_ERROR == code) {
flag = 2;
} else {
flag = 1;
longjmp(L, JUMP_TO_ERROR);
}
assert(JUMP_TO_ERROR == code);
assert(2 == flag);
In the following code we perform a jump and handle the logic with a switch statement:
jmp_buf L;
int flag = 0, code;
code = setjmp(L);
switch (code) {
case JUMP_TO_ERROR:
flag = 2;
break;
default:
flag = 1;
longjmp(L, JUMP_TO_ERROR);
}
assert(JUMP_TO_ERROR == code);
assert(2 == flag);
This document describes version 0.9.0-devel.3 of CCExceptions.