The strerror() Function

System errors happen. Your program accesses the operating system and . . . something goes wrong. When it does, the function returns -1 and your code must rely upon our old buddy errno to discover what went wrong and possibly output an informative error message.

For example, you use the rename() function to rename a file. A value other than 0 (success) is returned. The function’s man page says, “the global variable errno indicates the reason for the failure.” So your code sifts through the value present in errno to determine the cause: File Not Found, Permission Denied, and so on.

Working with errno is the handy perror() function, or as the French call it, le Pierre() function. It outputs a default message based on the errno error code, as well as an optional string of text that may help the user further understand the problem. For example:

perror("File renaming error");

This text is prepended to the system error message text, as in:

File renaming error: No such file or directory

The full message is output to the standard error device, stderr.

The perror() function has a sibling, strerror(). Here’s its man page format:

char *strerror(int errnum);

Given an integer value, errnum, the strerror() function returns a string describing the system error message. Like perror(), this function is prototyped in the stdio.h header file.

Valid values for errnum range from 1 through sys_nerr, a system variable. Values out of range generate the message Undefined error: followed by the invalid integer.

When I first learned of the range 1 through sys_nerr, I immediately wrote a program that outputs all the system error messages. Here’s the code:

2021_09_25-Lesson.c

#include <stdio.h>
#include <string.h>

int main()
{
    int x;

    puts("System error messages:");
    for( x=1; x<sys_nerr; x++ )
        printf("%3d: %s\n",x,strerror(x));

    return(0);
}

Line 9 loops through all valid system error messages, from 1 up through sys_nerr. On my system, I count 106 error messages. This size is the reason why I use the %3d placeholder in the printf() statement (Line 10), to ensure that the output width stays the same for each line of text output. Here are the first few lines of output:

System error messages:
  1: Operation not permitted
  2: No such file or directory
  3: No such process
  4: Interrupted system call
  5: Input/output error
  6: Device not configured
. . .

You can see that system error message 2 is No such file or directory, which is output with the perror() function when using rename() to rename a file that doesn’t exist. If the errno value of this message is 2, then I can connect the dots and see that the strerror() function’s errnum argument parallels the value of the global variable errno.

A quick peek into the definitions for errno in its header file reveals the following:

#define ENOENT    2      /* No such file or directory */

Ah. The universe makes sense.

While perror() allows you to output an errno value’s associated message along with a custom text message, the strerror() function swallows the errno value itself to output the system’s error message, nothing further. It’s not a unique tool, just another solution presented for the same problem.

Leave a Reply