C Standard Library setjmp.h

Intermediate
⏱️ 12 min read
📚 Updated: Jul 2026
🎯 5 Examples
<setjmp.h>

What You’ll Learn

<setjmp.h> defines non-local jumps: save where you are with setjmp, then snap back later with longjmp. It is powerful for deep error recovery (parsers, interpreters) but dangerous for everyday code because it bypasses normal returns and cleanup.

01

setjmp

Save spot.

02

longjmp

Jump back.

03

jmp_buf

Save buffer.

04

val

Return code.

05

volatile

Safe locals.

06

Caution

Not daily use.

Definition and Usage

A normal function returns with return. setjmp / longjmp let you jump back to an earlier point in the call stack without unwinding each function in between. The saved state lives in a jmp_buf object.

Think of setjmp(env) as planting a bookmark. The first time it runs, the bookmark is placed and the call returns 0. Later, longjmp(env, val) reopens the book at that bookmark; setjmp appears to return again, this time with a non-zero value derived from val.

💡
Beginner Tip

For divide-by-zero or bad user input, use if checks and return codes—not longjmp. This header teaches how C can jump across functions; most apps never need it.

📝 Syntax

Include the header:

C
#include <setjmp.h>

Types and macros

C
jmp_buf env;           /* buffer holding saved environment */

int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);

setjmp and longjmp may be implemented as macros. Do not use env as an expression with side effects, and do not return from the function that called setjmp if longjmp might still target that buffer.

Return rules

  • setjmp first call → returns 0.
  • longjmp(env, val)setjmp returns val, unless val == 0, then it returns 1.
  • Use distinct non-zero val values to signal different error types.

Critical restrictions

  • Only volatile local variables are reliable after longjmp.
  • Do not longjmp to a setjmp in a function that already returned.
  • Automatic variables in the function that called setjmp may be indeterminate unless volatile.
  • longjmp does not call fclose, free, etc.—clean up first or leak resources.

Headers and linking

  • #include <setjmp.h> — no special link flag.
  • Compile: gcc program.c -std=c11 -o program

⚡ Quick Reference

CallWhenReturns
setjmp(env)Plant bookmark0 first time
longjmp(env, n)Jump to bookmark(does not return)
setjmp after jumpResumedn (or 1 if n==0)
if (setjmp(env)==0)Normal pathRun protected code
else branchAfter longjmpError handler
Pattern
if (!setjmp(env)) { work(); }
else { handle(); }

Try / catch style

Signal
longjmp(env, 42)

Custom code

Safe var
volatile int flag;

After jump

Prefer
return -1;

Normal errors

Examples Gallery

Compile with gcc file.c -std=c11 -o out. These examples are for learning control flow—in production, prefer return codes and structured cleanup.

📚 Getting Started

Classic save-and-jump pattern from the reference.

Example 1 — Recover from Division by Zero

From the reference: longjmp unwinds from a nested function to a handler in main.

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

static jmp_buf env;

void divide(int a, int b) {
    if (b == 0) {
        longjmp(env, 1);
    }
    printf("Result: %d\n", a / b);
}

int main(void) {
    if (setjmp(env) == 0) {
        divide(10, 2);
        divide(10, 0);   /* triggers longjmp */
        printf("This line is skipped\n");
    } else {
        printf("Error: Division by zero!\n");
    }

    printf("Program continues after recovery\n");
    return 0;
}

How It Works

setjmp returns 0, so the first branch runs. The second divide calls longjmp(env, 1), which rewinds to setjmp—now it returns 1 and the else branch runs. Code after the failed divide is skipped.

Example 2 — Different longjmp Return Values

Pass error codes through val to distinguish failure reasons.

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

static jmp_buf env;

void fail(int code) {
    longjmp(env, code);
}

int main(void) {
    int err = setjmp(env);

    if (err == 0) {
        printf("Normal path\n");
        fail(42);
    } else if (err == 42) {
        printf("Caught error code 42\n");
    } else {
        printf("Unknown error %d\n", err);
    }

    return 0;
}

How It Works

longjmp(env, 42) makes setjmp return 42. If you passed 0, the standard requires setjmp to return 1 instead—so never use 0 as a meaningful error code.

📈 Practical Patterns

Deep stacks, better alternatives, and volatile locals.

Example 3 — Jump from a Deeply Nested Call

Three levels down—longjmp still reaches main’s setjmp.

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

static jmp_buf env;

void level3(void) {
    printf("  level3: about to longjmp\n");
    longjmp(env, 99);
}

void level2(void) {
    printf(" level2\n");
    level3();
    printf(" level2: never reached\n");
}

void level1(void) {
    printf("level1\n");
    level2();
}

int main(void) {
    if (setjmp(env) == 0) {
        level1();
    } else {
        printf("Recovered in main (code 99)\n");
    }
    return 0;
}

How It Works

level2 and level3 never return normally. The stack is unwound instantly to the setjmp in main. That power is why resource cleanup is your responsibility.

Example 4 — Prefer Return Codes for Simple Errors

Same divide check without setjmp—clearer for beginners.

C
#include <stdio.h>

int safe_divide(int a, int b, int *out) {
    if (b == 0) {
        return -1;
    }
    *out = a / b;
    return 0;
}

int main(void) {
    int result;

    if (safe_divide(10, 2, &result) == 0) {
        printf("Result: %d\n", result);
    }

    if (safe_divide(10, 0, &result) != 0) {
        printf("Error: Division by zero!\n");
    }

    return 0;
}

How It Works

Same user-visible result, easier to read and debug. Use this pattern unless you have many nested layers and a compelling reason to jump.

Example 5 — volatile Locals After longjmp

Demonstrates why the standard requires volatile for locals you read after a jump.

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

static jmp_buf env;

int main(void) {
    volatile int counter = 0;
    int plain = 0;

    if (setjmp(env) == 0) {
        counter++;
        plain++;
        longjmp(env, 1);
    }

    printf("volatile counter = %d (reliable)\n", counter);
    printf("plain may be unreliable after longjmp (value: %d)\n", plain);

    return 0;
}

How It Works

counter is volatile, so its value after longjmp is defined. plain might not reflect the increment—behavior is undefined for non-volatile locals in the function that called setjmp.

🚀 Common Use Cases

  • Expression parsers — abort parse on syntax error deep in recursion.
  • Interpreters / VMs — bail out to a top-level REPL on fatal script errors.
  • Unit test frameworks — some C test runners use jumps for failure recovery.
  • Legacy codebases — error handling before widespread return-code discipline.
  • Teaching — understand stack unwinding vs exceptions in other languages.
  • Not recommended — everyday validation, file I/O, or network errors (use return codes).

🧠 How setjmp.h Works

1

setjmp saves context

Stack pointer, return address, and registers go into jmp_buf.

Bookmark
2

Normal code runs

Functions call each other; an error may occur deep in the stack.

Execute
3

longjmp restores

Context restored; execution resumes as if setjmp just returned val.

Jump
=

Handler runs

The else branch or non-zero setjmp path handles the error.

📝 Notes

  • setjmp / longjmp are not C++ exceptions—no destructors, no RAII.
  • Mark locals volatile if their values matter after a jump.
  • Never longjmp out of a function that has already returned from the setjmp caller.
  • Free memory and close files before longjmp, or you leak resources.
  • Using setjmp in multiple threads on the same jmp_buf is unsafe.
  • POSIX offers sigsetjmp / siglongjmp when jumping from signal handlers—see signal.h.

⚡ Optimization

setjmp saves registers—not free, but usually cheaper than deep manual error propagation in huge recursive parsers. For simple functions, return codes are faster to execute and far easier for the compiler to optimize.

Conclusion

<setjmp.h> provides non-local jumps via setjmp and longjmp. Plant a bookmark with jmp_buf, jump back with an error code, and handle it in one place—but respect volatile, cleanup, and scope rules.

For most C programs, return values and errno are the right tools. Know setjmp for reading legacy code and specialized parsers—not as your default error handler.

💡 Best Practices

✅ Do

  • Use distinct non-zero val codes in longjmp
  • Declare critical locals as volatile
  • Clean up resources before jumping
  • Keep setjmp buffers in scope for the jump lifetime
  • Prefer return codes for ordinary errors

❌ Don’t

  • Use longjmp to skip fclose / free
  • Jump to a setjmp after its function returned
  • Rely on non-volatile locals after a jump
  • Replace every if (error) with longjmp
  • Share one jmp_buf across threads

Key Takeaways

Knowledge Unlocked

Five things to remember about setjmp.h

Non-local jumps in C, explained simply.

5
Core concepts
📚 02

longjmp

Jump back.

Restore
📈 03

val

Error code.

Signal
📄 04

volatile

Safe vars.

Rules
🌐 05

return

Prefer this.

Daily use

❓ Frequently Asked Questions

setjmp.h provides setjmp and longjmp for non-local jumps: save the current execution context in a jmp_buf with setjmp, then later jump back to that point with longjmp—like a time machine for your call stack, but with strict rules.
On the first direct call, setjmp returns 0. When longjmp jumps back, setjmp returns again with the val argument you passed to longjmp—unless val is 0, in which case setjmp returns 1 instead.
Similar idea (jump elsewhere) but different scope. goto only moves within one function. setjmp/longjmp can unwind across function calls—but only to a still-active setjmp in the same call chain. Misuse breaks the stack.
Only volatile locals are guaranteed to keep meaningful values after longjmp. Other locals may be corrupted or stale. Never longjmp past a function that has returned—the jmp_buf becomes invalid.
Usually no. Prefer return codes, errno, and normal cleanup. setjmp/longjmp skip destructors and fclose calls unless you clean up manually. Reserve them for parsers, interpreters, or legacy patterns—not everyday validation errors.
Yes, if setjmp was called in an ancestor that is still active (has not returned). longjmp cannot jump into a setjmp in a function that already returned—that jmp_buf is undefined to use.
Did you know?

Lua’s C API and some Scheme interpreters use setjmp-style mechanisms internally for protected calls. The C standard library itself almost never uses longjmp for you—when malloc fails it returns NULL, and when sqrt(-1) is invalid it returns NaN. That is the style most application code should follow.

Explore C Standard Library Headers

Continue with signal.h or browse the library index.

Standard Library Index →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful