Error Handling Techniques
Understanding Error Handling in C
Error handling is a critical aspect of robust software development, allowing programs to gracefully manage unexpected situations and prevent system crashes.
Error Handling Mechanisms
1. Return Value Checking
#include <stdio.h>
#include <stdlib.h>
FILE* safe_file_open(const char* filename, const char* mode) {
FILE* file = fopen(filename, mode);
if (file == NULL) {
fprintf(stderr, "Error: Cannot open file %s\n", filename);
return NULL;
}
return file;
}
int main() {
FILE* log_file = safe_file_open("system.log", "r");
if (log_file == NULL) {
// Handle error condition
exit(EXIT_FAILURE);
}
// File operations
fclose(log_file);
return 0;
}
2. Error Codes and Enums
typedef enum {
ERROR_SUCCESS = 0,
ERROR_FILE_NOT_FOUND = -1,
ERROR_PERMISSION_DENIED = -2,
ERROR_MEMORY_ALLOCATION = -3
} ErrorCode;
ErrorCode process_data(const char* filename) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
return ERROR_FILE_NOT_FOUND;
}
// Process file
fclose(file);
return ERROR_SUCCESS;
}
Error Handling Strategies
Strategy |
Description |
Advantages |
Return Codes |
Use integer or enum return values |
Simple, explicit error communication |
Error Logging |
Record error details |
Helps in debugging and monitoring |
Graceful Degradation |
Provide fallback mechanisms |
Improves user experience |
Error Handling Workflow
graph TD
A[Function Call] --> B{Error Occurred?}
B -->|Yes| C[Log Error]
B -->|No| D[Continue Execution]
C --> E[Handle Error]
E --> F[Notify User]
E --> G[Attempt Recovery]
Advanced Error Handling Techniques
1. Error Structures
typedef struct {
int error_code;
char error_message[256];
} ErrorInfo;
ErrorInfo validate_input(const char* input) {
ErrorInfo error = {0};
if (input == NULL) {
error.error_code = -1;
snprintf(error.error_message, sizeof(error.error_message),
"Input is NULL");
}
return error;
}
2. Signal Handling
#include <signal.h>
void segmentation_fault_handler(int signum) {
fprintf(stderr, "Caught segmentation fault. Cleaning up...\n");
// Perform cleanup operations
exit(signum);
}
int main() {
signal(SIGSEGV, segmentation_fault_handler);
// Rest of the program
return 0;
}
Best Practices for LabEx Developers
- Always check return values
- Use meaningful error messages
- Log errors for debugging
- Implement comprehensive error recovery
- Avoid exposing sensitive system information
Common Error Handling Pitfalls
- Ignoring return values
- Inadequate error logging
- Incomplete error recovery
- Inconsistent error reporting
Conclusion
Effective error handling is not just about preventing crashes, but about creating resilient and user-friendly software that can gracefully manage unexpected situations.