Sage-Code Laboratory
index<--

C Error handling

In C there is very little error management support. C does not have try/except statement like Java or Python. To handle errors in C you must analyze the function result and the global error number that can be set by a function during execution.

Design flaw?

When C was invented the main focus was to get as much efficiency as possible without syntax overhead. Therefore in C language you will not find safety mechanics present in higher level languages of today. 

Error handling require high level abstractions not available in C. However a good programmer will be concern about making safe applications. In this article we explain the little support C offers for error handling.

Error code

Most functions indicate that they detected an error by returning a special value, typically NULL for functions that return pointers, and −1 for functions that return integers. In addition to this you can set "errno" global variable. Any non zero value for "errno" after a function call will indicate an error. 

Various system errors are defined in <error.h> header file. You can use these codes to compare errno and do some actions depending on the error code. It is a good practice, to set errno to zero (0) before computation or action. After you can check errno to verify if operation was successful.

Error message

Only error code will not be good enough for user to understand the error. Therefore a good practice is to send an error message to consol or to standard error stream. This can be redirected by the user into a log file using a script or command line arguments.

Standard C provide two functions that are useful to produce the error message:

Example:

#include <stdio.h>
#include <errno.h>
#include <string.h>
extern int errno; //global variable
int main () {
    FILE * f;
    //try to open file "test"
    f = fopen ("test", "r");
    //check if operation was successful
    if (f == NULL) {
        fprintf(stderr, "Error: %d, %s\n", errno, strerror(errno));
    } else {
        fclose (f);
    }
    return 0;
}

Note: It is better to have a preventive design in your application than a reactive design. What that means is you can check parameter values before you use these values as parameters to call other functions or computations to prevent possible errors.

A reactive design uses whatever values and analyze later if the computation was successful. After the fact you may have less information available about the reason the computation was failed. However it is a good practice to check errno every time even if you use preconditions to prevent the errors in the first place.


Read next: Type Casting