Setjmp.h

From Wikipedia, the free encyclopedia

C++ Standard Library headers
C Standard Library headers
assert.h
ctype.h
errno.h
float.h
limits.h
locale.h
math.h
setjmp.h
signal.h
stdarg.h
stddef.h
stdio.h
string.h
stdlib.h
time.h
The correct title of this article is setjmp.h. The initial letter is shown capitalized due to technical restrictions.

setjmp.h is a header defined in the C standard library to provide "non-local jumps" (control flow) outside of the normal function call and return sequence, typically to implement a crude form of exception handling. The paired functions setjmp and longjmp provide this functionality through first saving the environment with setjmp from which longjmp can "jump" to.

The typical use for setjmp/longjmp is for exception handling - by calling longjmp, the program can jump out of many levels of nested function calls without having to go to the trouble of setting flag variables which need to be checked in each function. A problem with the use of setjmp/longjmp is that cleanup (closing file descriptors, flushing buffers, freeing heap-allocated memory, etc.) will not be conducted.

Neither setjmp nor longjmp save or restore the current set of blocked signals - if a program employs signal handling it should use sigsetjmp/siglongjmp.

Compared to mechanisms in higher-level programming languages such as Java, C++, 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.

Contents

[edit] Member functions

int setjmp(jmp_buf env) Sets up the local jmp_buf buffer and initializes it for the jump. This macro saves the program's calling environment in the environment buffer specified by the env argument for later use by longjmp. If the return is from a direct invocation, setjmp returns 0. If the return is from a call to longjmp, setjmp returns a nonzero value.
void longjmp(jmp_buf env, int value) Restores the context of the environment buffer env that was saved by invocation of the setjmp macro in the same invocation of the program. Invoking longjmp from a nested signal handler is undefined. The value specified by value is passed from longjmp to setjmp. After longjmp is completed, program execution continues as if the corresponding invocation of setjmp had just returned. If the value passed to longjmp is 0, setjmp will behave as if it had returned 1; otherwise, it will behave as if it had returned value.

setjmp saves the current execution state into a structure of type jmp_buf; later, a longjmp call can transfer control to the point immediately after the call to setjmp. The (apparent) return value from setjmp indicates whether control reached that point normally or from a call to longjmp; this allows the use of a common idiom, placing the setjmp in the condition of an if/else block, similar to that with the fork system call.

[edit] Member types

jmp_buf An array type suitable for holding the information needed to restore a calling environment.

[edit] Example

This is an example of setjmp usage, in which switch (setjmp(buf)) operates similarly to a try-catch block in some other languages. The call to longjmp is analogous to a throw statement, allowing an exception status to be returned directly from arbitrary levels of nested function calls. Notice that unlike some other languages, there is no provision for finally blocks.

Also, notice that setjmp is invoked by itself inside the controlling expression of the switch statement; this is one of a very few ways setjmp is allowed to be invoked in a conforming C program. The reason for this restriction is to limit the need to save and restore the values of temporary registers or stack locations around the setjmp call.[1]

#include <stdio.h>
#include <setjmp.h>

void first(void);
void second(void);

/* Global "environment" variable; this must be in scope if longjmp is to be called. */
static jmp_buf buf;

int main (int argc, char **argv)
{
    int specific_status = 0;
    switch (setjmp(buf)) {
        case 0: {
            /* Run code that may signal failure via longjmp. */
            printf("calling first\n");
            first();
            printf("first succeeded\n");  /* not reached */
            break;
        }
        case 3:
            specific_status = 3;
            /* fallthrough */
        default: {
            /* Take any action required on failure. */
            if (specific_status != 0)
              printf("first failed, status %d\n", specific_status);
            else
              printf("first failed, status nonzero\n");
            break;
        }
    }
    return 0;
}

void first(void)
{
    printf("calling second\n");
    /* If second calls longjmp, this code has no way of knowing,
       so it can't perform any cleanup. */
    second();
    printf("second succeeded\n");  /* not reached */
}

void second(void)
{
    /* Normally the code here would try to do something useful and
       longjmp on failure, but here we're just demonstrating
       longjmp's ability to return from nested function calls.
       Note that this is not as general as a throw in other languages
       since it needs to be aware of the jmp_buf to be used to jump
       back to a specific caller.
       Alternatively the jmp_buf could be in main scope and passed in 
       the function parameters, making error handling more general 
       but complicating function calls. */
    longjmp(buf, 3);
}

[edit] References

  1. ^ C99 Rationale, version 5.10, April 2003:
    Unfortunately, any implementation of setjmp as a conventional called function cannot know enough about the calling environment to save any temporary registers or dynamic stack locations used part way through an expression evaluation. ... The temporaries may be correct on the initial call to setjmp, but are not likely to be on any return initiated by a corresponding call to longjmp. These considerations dictated the constraint that setjmp be called only from within fairly simple expressions, ones not likely to need temporary storage.[1]

[edit] See also