C Programming/Error handling

C does not provide direct support for error handling (also known as exception handling). By convention, the programmer is expected to prevent errors from occurring in the first place, and test return values from functions. For example, -1 and NULL are used in several functions such as socket (Unix socket programming) or malloc respectively to indicate problems that the programmer should be aware about. In a worst case scenario where there is an unavoidable error and no way to recover from it, a C programmer usually tries to log the error and "gracefully" terminate the program.

There is an external variable called "errno", accessible by the programs after including  - that file comes from the definition of the possible errors that can occur in some Operating Systems (e.g. Linux - in this case, the definition is in include/asm-generic/errno.h) when programs ask for resources. Such variable indexes error descriptions accessible by the function 'strerror( errno )'.

The following code tests the return value from the library function malloc to see if dynamic memory allocation completed properly:

The code snippet above shows the use of the return value of the library function malloc to check for errors. Many library functions have return values that flag errors, and thus should be checked by the astute programmer. In the snippet above, a NULL pointer returned from malloc signals an error in allocation, so the program exits. In more complicated implementations, the program might try to handle the error and try to recover from the failed memory allocation.

Preventing divide by zero errors
A common pitfall made by C programmers is not checking if a divisor is zero before a division command. The following code will produce a runtime error and in most cases, exit.

In ordinary arithmetic division by zero is undefined. Because of this, you must check or make sure that a divisor is never zero. Alternatively, for *nix processes, you can stop the OS from terminating your process by blocking the SIGFPE signal.

The code below fixes this by checking if the divisor is zero before dividing.

Signals
In some cases, the environment may respond to a programming error in C by raising a signal. Signals are events raised by the host environment or operating system to indicate that a specific error or critical event has occurred (e.g. a division by zero, interrupt, and so on.) However, these signals are not meant to be used as a means of error catching; they usually indicate a critical event that will interfere with normal program flow.

To handle signals, a program needs to use the signal.h header file. A signal handler will need to be defined, and the signal function is then called to allow the given signal to be handled. Some signals that are raised to an exception within your code (e.g. a division by zero) are unlikely to allow your program to recover. These signal handlers will be required to instead ensure that some resources are properly cleaned up before the program terminates.

The C Standard Library only defines six signals; Unix systems define 15 more. Each signal has a number, called a signum, associated with it. Here are a few common ones:

Signals are handled with the signal function, from the signal.h library. Its syntax is:

Signals can be raised with raise or kill. raise sends the signal to the current process; kill sends it to a specific process.

''Note that signal</tt> is now deprecated in favor of <tt>sigaction</tt>, due to a lack of portability between Unix systems and potential for unexpected behavior. However, as <tt>sigaction</tt>'s use is more complicated, we will stick with <tt>signal</tt> to illustrate the concept here.''

To understand how signals work, here's a simple example:

Try compiling and testing this on your machine; after you see "Sleeping...", send the interrupt signal by pressing <tt>ctrl + c</tt>.

Here's a more complex example. This creates a signal handler and raises the signal:

setjmp
The setjmp function can be used to emulate the exception handling feature of other programming languages. The first call to setjmp stores a reference point to the current execution point, and is valid as long as the function containing setjmp doesn't return or exit. A call to longjmp causes the execution to return to the point of the associated setjmp call.

<tt>setjmp</tt> takes a `jmp_buf` (a type that will store an execution context) as an argument, and returns <tt>0</tt> the first time it runs (i.e., when it sets the return point). When it runs a second time - when <tt>longjmp</tt> is called - it then returns the value passed to <tt>longjmp</tt>.

<tt>longjmp</tt> takes a `jmp_buf` as an argument (one that's already been passed to <tt>setjmp</tt>), and a value to pass to <tt>setjmp</tt> to return.

Try running this with a compiler on your own machine.

The values of non-volatile variables may be corrupted when setjmp returns from a longjmp call.

While setjmp and longjmp may be used for error handling, it is generally preferred to use the return value of a function to indicate an error, if possible. setjmp and longjmp are most useful when errors occur in deeply nested function calls, and it would be tedious to check return values all the way back to the point you wish to return to.