Codehavn

Kristofer's Code Writings

setjmp and longjmp are C library functions that implement a form of non-local control transfer - essentially allowing you to jump from deep within a call stack back to an earlier point, bypassing normal function return mechanisms.

What they are

setjmp(jmp_buf env) - Saves the current execution context (registers, stack pointer, program counter) into a jmp_buf structure and returns 0 initially.

longjmp(jmp_buf env, int val) - Restores the execution context saved in env, causing execution to resume at the setjmp call, but this time setjmp returns val (or 1 if val is 0).

The jmp_buf is an opaque data type that stores the machine state - typically registers and stack information needed to restore execution.

Why they're used

  1. Error handling before exceptions - Provides a way to bail out of deeply nested function calls when an error occurs, similar to exceptions in higher-level languages.

  2. Early returns from complex call chains - When you need to abort processing and return to a known safe point.

  3. Implementing coroutines/cooperative multitasking - Though this is quite advanced and error-prone.

  4. Signal handling - Sometimes used in signal handlers to return to a safe execution point.

How they work

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

jmp_buf error_buf;

void deep_function() {
    printf("About to jump back\n");
    longjmp(error_buf, 42);  // Jump back with value 42
    printf("This never executes\n");
}

void middle_function() {
    deep_function();
    printf("This also never executes\n");
}

int main() {
    int result = setjmp(error_buf);
    
    if (result == 0) {
        printf("First time through setjmp\n");
        middle_function();
    } else {
        printf("Jumped back with value: %d\n", result);
    }
    
    return 0;
}

Important caveats

  1. Undefined behavior with local variables - Local variables in the function containing setjmp may have indeterminate values after longjmp unless they're volatile.

  2. Stack unwinding issues - Unlike exceptions, longjmp doesn't call destructors or cleanup code in intermediate functions.

  3. Jumping constraints - You can only longjmp to a setjmp that's still active on the stack. Jumping to an expired stack frame is undefined behavior.

  4. Signal safety - longjmp from a signal handler has restrictions and portability issues.

Why they're generally avoided

Modern C programming typically avoids setjmp/longjmp because:

They're still occasionally useful for implementing interpreters, parsers with error recovery, or in systems programming where you need emergency bailout mechanisms, but they should be used sparingly and with great care.