ProgrammingC Developer

How is error handling implemented in the C language? What are the differences between setjmp/longjmp, errno, and return error codes? When to use each approach?

Pass interviews with Hintsage AI assistant

Answer

In C, there is no built-in support for exceptions; error handling is implemented in the following ways:

  1. Returning error codes (usually via the function's return value) Example:

    int read_file(const char *name) { FILE *f = fopen(name, "r"); if (!f) return -1; // Error // ... fclose(f); return 0; // Success }
  2. Using the global variable errno When an error occurs, standard functions often set the global variable errno. Example:

    FILE *fp = fopen("nofile", "r"); if (!fp) { perror("File error"); // errno indicates the reason }
  3. setjmp/longjmp — the throw "exception" mechanism (execution context is saved and restored) Used for complex cases (e.g., cross-level emergency termination). Rarely used because it complicates the code and can lead to resource leaks.

    #include <setjmp.h> jmp_buf buf; if (setjmp(buf) == 0) { // ... longjmp(buf, 1); // Jumps to if (setjmp(...)) } else { // Error handling }
  • Returning error codes — the main method, simple and safe.
  • errno — convenient for library functions.
  • setjmp/longjmp — for specific cases (complex libraries or interpreters).

Trick Question

What will the following code output?

#include <stdio.h> #include <setjmp.h> jmp_buf buf; void func() { longjmp(buf, 5); } int main() { int val = setjmp(buf); printf("val=%d\n", val); if (val == 0) func(); return 0; }

Answer:

  • On the first call, setjmp returns 0 and the function func is called.
  • In it, longjmp(buf, 5) is executed, and execution returns to setjmp, which now returns 5.
  • Final output:
    val=0
    val=5
    

Examples of real errors due to ignorance of the nuances of the topic


Story In one library, a manual resource cleanup mechanism was implemented on error only based on the return code. However, the programmer forgot to handle an error when returning not from the main thread, but from a callback (via setjmp/longjmp), resulting in memory leaks and file locks.


Story In a network application, the check for errno after a socket operation was missed. As a result, there was a false diagnosis: the variable errno retained an old incorrect value from the previous function.


Story The team implemented complex nesting with multiple return code error points but did not adhere to the convention regarding return values (zero/negative values). Some errors were interpreted as successful, leading to unpredictable service failures.