Day 11: Error Handling and Exception-Like Mechanisms in C

Indradeep Halder
4 min readOct 25, 2023

--

Recap from Day 10:

Yesterday we have learnt about the secrets of bitwise operations and preprocessor directives. Today, we’re focusing on error handling and introducing exception-like mechanisms in C.

Credit : the odd bit blog

Agenda for Today:

  1. Error Handling Basics:
  • The importance of handling errors in programming.
  • Using return values and error codes.

2. Introduction to Exception-Like Mechanisms:

  • Simulating exceptions in C.
  • The role of setjmp and longjmp

Let’s Dive In!

Introduction:

Error handling is an essential aspect of programming that allows developers to handle unexpected situations and ensure the smooth execution of their code. In the C programming language, error handling is primarily achieved through the use of error codes and exception-like mechanisms. In this blog, we will explore the various techniques and best practices for error handling in C.

  1. Error Codes: Error codes are a common method of error handling in C. They are integer values that indicate the success or failure of a function or operation. Conventionally, a return value of 0 represents success, while any non-zero value indicates an error. Developers can define their own error codes or use predefined ones from libraries or the operating system.

Example:

int divide(int a, int b, int* result) {
if (b == 0) {
return -1; // Error: Division by zero
}
*result = a / b;
return 0; // Success
}

2. errno and perror: The C standard library provides the errno variable, which is set by certain library functions to indicate specific errors. Developers can use the perror function to print a descriptive error message based on the value of errno. This mechanism is particularly useful when dealing with system calls or library functions that set errno.

Example:

#include <stdio.h>
#include <errno.h>

int main() {
FILE* file = fopen("nonexistent.txt", "r");
if (file == NULL) {
perror("Error");
printf("Error code: %d\n", errno);
}
return 0;
}

3. Signal Handling: C provides signal handling mechanisms to deal with asynchronous events, such as interrupts or abnormal program termination. By registering signal handlers, developers can define custom actions to be taken when a specific signal is received. This allows for graceful termination or recovery from exceptional situations.

Example:

#include <stdio.h>
#include <signal.h>

void signalHandler(int signal) {
printf("Received signal: %d\n", signal);
// Custom error handling logic
}

int main() {
signal(SIGINT, signalHandler); // Register signal handler for SIGINT
while (1) {
// Main program logic
}
return 0;
}

4. setjmp and longjmp: The setjmp and longjmp functions provide a non-local jump mechanism that can be used for error handling in C. setjmp sets a program point to which longjmp can later jump, effectively bypassing the normal function call and return sequence. This technique is useful for handling exceptional conditions that occur deep within nested function calls.

Example:

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

jmp_buf jumpBuffer;

void errorFunction() {
longjmp(jumpBuffer, 1); // Jump back to setjmp point
}

int main() {
if (setjmp(jumpBuffer) == 0) {
// Normal program flow
errorFunction(); // Simulate an error
} else {
// Error handling code
printf("Error occurred\n");
}
return 0;
}

Hands-On Exercise:

Let’s enhance our previous program to handle errors gracefully. If the user enters a non-numeric value, we’ll catch the error and display a helpful message.

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

// Using setjmp and longjmp for exception-like handling
jmp_buf exceptionBuffer;

int safeReadInt() {
int value;
if (setjmp(exceptionBuffer) == 0) {
// Try to read an integer
printf("Enter an integer: ");
scanf("%d", &value);

// Check if the input was numeric
if (scanf("%*c") != 0) {
// Non-numeric input, raise an exception
printf("Error: Non-numeric input.\n");
longjmp(exceptionBuffer, 1);
}

return value;
} else {
// Handle the exception
return 0; // Return a default value or an error code
}
}

int main() {
int number;

// Use safeReadInt to handle errors
number = safeReadInt();

printf("You entered: %d\n", number);

return 0;
}

Conclusion:

Error handling is crucial for robust and reliable software development. In C, error codes, errno, signal handling, and setjmp/longjmp provide mechanisms to handle errors and exceptional situations. By understanding and utilizing these techniques effectively, developers can enhance the stability and resilience of their C programs.

What’s Next?

Tomorrow, we’ll explore multi-file programming and how to organize your code into separate files for better modularity. If you have questions or want to share your code, drop a comment below. If you want to become a part of my learning journey consider giving me a follow and share it with others.

Further Reading:

  1. Error Handeling in C
  2. The GNU C Library Documentation
  3. “The C Programming Language” by Brian W. Kernighan and Dennis M. Ritchie

--

--