Noeud:Error Handling, Noeud « Next »:, Noeud « Previous »:Input and Output, Noeud « Up »:The GNU C Library



Error Handling

UNIX programs always return an exit code. Exit codes usually go unnoticed, but are always present. They are most often used by shell scripts and by make, which may take some alternative action if the program doesn't finish correctly.

By convention, most programs return an exit code of zero to indicate normal completion. Nonzero exit codes usually mean that an error has occurred. There are some notable violations of this convention (e.g., cmp and diff), but we recommend you obey it. C shell users can print exit codes by entering the command:

     % echo $status
     

If you use the Bourne shell (sh) or a derivative like bash, you can print the exit code with the command:

     $ echo $?
     

When you are writing a program, to have it return an error code, call the function exit, with the error code as an argument:

     int code;
     
     exit (code);
     

Although the error code is an int, its value should be between 0 and 255.

Functions aren't that different from programs: their returned value indicates whether they succeeded or failed. If you want to write healthy code, you should always check the value returned from a function. The code below shows one way to test for an error:

     #include <stdio.h>
     
     /* write to standard output and check for error */
     if (printf (...) == EOF) exit (1); /* output failed; terminate */
     /* normal processing continues */
     ...
     

The manual page for printf says that it returns the constant EOF if it fails; if it succeeds, it returns the number of bytes transmitted. If you look in stdio.h, you'll see that EOF is defined as -1. As a rule, a positive or zero return value indicates success; a negative value indicates failure. However, there are many exceptions to this convention. Check the manual page, and if a symbolic constant (like EOF) is available, use that rather than a hard-wired constant.

If you want more information about what went wrong with your function, you can inspect the errno variable. When a system call fails, it stores an error code in errno. UNIX then terminates the system call, returning a value that indicates something has gone wrong - as we just discussed. Your program can access the error code in errno, figure out what went wrong, and (possibly) recover, as in the example below:

     #include <stdio.h>
     #include <errno.h>
     
     FILE *fd;
     int fopen_errno;
     
     main (int argc, char **argv)
     {
       /* try opening the file passed by the user as an argument */
       if ((fd=fopen (argv[1], "r")) == NULL)
         {
           /* test errno, and see if we can recover */
           fopen_errno = errno; /* save errno */
           if (fopen_errno == ENOENT) /*no such file or directory*/
             {
               /* get a filename from the user and try opening again */
               ...
     	}
           /* otherwise, it's an unknown error */
           else
             {
     	  perror ("Invalid input file");
     	  exit (1);
             }
         }
       /* normal processing continues */
     }
     
     Example 2.15: Use of errno
     

On UNIX systems, the header file errno.h defines all possible system error values. Note that this code immediately copies errno to a local variable. This is a good idea, since errno is reset whenever a system call from your process fails, and there's no way to recover its previous value.

Another way to use the error number, without examining it yourself, is to call perror, which sends a message describing the error to the standard error I/O stream. It's used like this:

     #include <stdio.h>
     
     perror ("prefix to message");
     

The prefix to message given as an argument to perror is printed first; then a colon; then the standardized message. For example, if the previous function call failed with the errno ENAMETOOLONG because the user passed a long string of garbage as an argument, the function call perror ("Invalid input file"); would result in the output:

     Invalid input file: File name too long
     

void error (int status, int errnum, const char *format, ...) glibc function

void error_at_line (int status, int errnum, const char *filename, unsigned int lineno, const char *format, ...) glibc function