Setjmp/longjmp
From Free net encyclopedia
setjmp
and longjmp
are functions used in
C programming language for non-local exits
or exception handling.
Reasons for use
As an example of a situation where a non-local exit can be useful, suppose you have an interactive program that has a main loop that prompts for and executes commands. Suppose the read command reads input from a file, doing some lexical analysis and parsing of the input while processing it. If a low-level input error is detected, it would be useful to be able to return immediately to the main loop instead of having to make each of the lexical analysis, parsing, and processing phases all have to explicitly deal with error situations initially detected by nested calls.
On the other hand, if each of these phases has to do a substantial amount of cleanup when it exits—such as closing files, deallocating buffers or other data structures, and the like—then it can be more appropriate to do a normal return and have each phase do its own cleanup, because a non-local exit would bypass the intervening phases and their associated cleanup code entirely. Alternatively, you could use a non-local exit but do the cleanup explicitly either before or after returning to the main loop.
In some ways, a non-local exit is similar to using the
return
statement to return from a function. But while
return
abandons only a single function call, transferring
control back to the point at which it was called, a non-local exit can
potentially abandon many levels of nested function calls.
Compared to mechanisms in higher-level programming languages such as Java, C#, and particularly in older high-level languages such as Algol 60 and Common Lisp, the setjmp
/longjmp
technique is archaic. These languages provide far more powerful exception handling techniques.
Workings
You identify return points for non-local exits by calling the function
setjmp
. This function saves information about the
execution environment in which the call to setjmp
appears
in an object of type jmp_buf
. Execution of the program
continues normally after the call to setjmp
, but if an
exit is later made to this return point by calling
longjmp
with the corresponding jmp_buf
object, control is transferred back to the point where
setjmp
was called. The return value from
setjmp
is used to distinguish between an ordinary return
and a return made by a call to longjmp
, so calls to
setjmp
usually appear in an if
statement.
Example usage
Here is how the example program described above might be set up:
#include <setjmp.h> #include <stdlib.h> #include <stdio.h> jmp_buf main_loop; void abort_to_main_loop (int status) { longjmp (main_loop, status); } int main (void) { while (1) if (setjmp (main_loop)) puts ("Back at main loop...."); else do_command (); } void do_command (void) { char buffer[128]; if (fgets (buffer, 128, stdin) == NULL) abort_to_main_loop (-1); else exit (EXIT_SUCCESS); }
The function abort_to_main_loop
causes an immediate
transfer of control back to the main loop of the program, no matter
where it is called from.
The flow of control inside the main
function may appear a
little mysterious at first, but it is actually a common idiom with
setjmp
. A normal call to setjmp
returns
zero, so the else
clause of the conditional is
executed. If abort_to_main_loop
is called somewhere
within the execution of do_command
, then it actually
appears as if the same call to setjmp
in
main
were returning a second time with a value of -1.
So, the general pattern for using setjmp
looks something
like:
if (setjmp (BUFFER)) /* Code to clean up after premature return. */ ... else /* Code to be executed normally after setting up the return point. */ ...