Error Handling
Understanding Error Handling
Error handling is a critical aspect of robust C programming that involves anticipating, detecting, and resolving unexpected situations during program execution.
Basic Error Handling Mechanisms
1. Return Value Checking
#include <stdio.h>
#include <stdlib.h>
FILE* safe_file_open(const char* filename) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
return file;
}
int main() {
FILE* file = safe_file_open("example.txt");
// File handling logic
fclose(file);
return 0;
}
Error Handling Strategies
Error Handling Approaches
Approach |
Description |
Pros |
Cons |
Return Codes |
Using integer return values |
Simple implementation |
Limited error details |
Error Pointers |
Passing error information |
More flexible |
Requires careful management |
Exception-like |
Custom error handling |
Comprehensive |
More complex |
Error Handling Workflow
graph TD
A[Potential Error Condition] --> B{Error Occurred?}
B -->|Yes| C[Capture Error Details]
B -->|No| D[Continue Execution]
C --> E[Log Error]
E --> F[Handle/Recover]
F --> G[Graceful Shutdown/Retry]
Advanced Error Handling Techniques
1. Error Logging
#include <errno.h>
#include <string.h>
void log_error(const char* message) {
fprintf(stderr, "Error: %s\n", message);
fprintf(stderr, "System Error: %s\n", strerror(errno));
}
int main() {
FILE* file = fopen("nonexistent.txt", "r");
if (file == NULL) {
log_error("Failed to open file");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
2. Custom Error Handling Structure
typedef struct {
int code;
char message[256];
} ErrorContext;
ErrorContext global_error = {0, ""};
void set_error(int code, const char* message) {
global_error.code = code;
strncpy(global_error.message, message, sizeof(global_error.message) - 1);
}
int process_data() {
// Simulated error condition
if (some_error_condition) {
set_error(100, "Data processing failed");
return -1;
}
return 0;
}
Error Handling Best Practices
- Always check return values
- Use meaningful error messages
- Implement comprehensive logging
- Provide clear error recovery paths
- Avoid exposing sensitive system details
Common Error Handling Functions
perror()
strerror()
errno
LabEx Error Handling Recommendations
At LabEx, we recommend:
- Consistent error handling approach
- Comprehensive error documentation
- Implementing multiple layers of error checking
- Using static analysis tools to detect potential errors
Defensive Programming Principles
- Validate all input
- Check resource allocation
- Implement timeout mechanisms
- Provide fallback strategies
Error Handling in System Calls
#include <unistd.h>
#include <errno.h>
ssize_t safe_read(int fd, void* buffer, size_t count) {
ssize_t bytes_read;
while ((bytes_read = read(fd, buffer, count)) == -1) {
if (errno != EINTR) {
perror("Read error");
return -1;
}
}
return bytes_read;
}