What is `perror` in C?

You may see calls to perror in C code. What is it?

#include <stdio.h>
void perror(char const * s);

A call to perror("foo") will print "foo: " to stderr, then will print a human-readable description of the err in errno (the global error number written to by syscalls and library functions). For example:

#include <stdio.h>
int main() {
  FILE* fp = fopen("nonexistent", "r");
  if (fp == NULL) {
    perror("Could not open file");
    return 1;
  }
  // ...
  return 0;
}

This prints:

% ./a.out
Could not open file: No such file or directory

The perror function gets the string "No such file or directory" from a global error table:

#include <errno.h>
const char * const sys_errlist[];
int sys_nerr;

We can print these out:

#include <stdio.h>
int main() {
  for (size_t i = 0; i < sys_nerr; i++) {
    printf("%*zu = %s\n", 3, i, sys_errlist[i]);
  }
}

We get all the errors!:

% ./a.out
  0 = Undefined error: 0
  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
  7 = Argument list too long
  8 = Exec format error
  9 = Bad file descriptor
 10 = No child processes
 11 = Resource deadlock avoided
 12 = Cannot allocate memory
 13 = Permission denied
 14 = Bad address
 15 = Block device required
 16 = Resource busy
 17 = File exists
 18 = Cross-device link
 19 = Operation not supported by device
 20 = Not a directory
 21 = Is a directory
 22 = Invalid argument
 23 = Too many open files in system
 24 = Too many open files
 25 = Inappropriate ioctl for device
 26 = Text file busy
 27 = File too large
 28 = No space left on device
 29 = Illegal seek
 30 = Read-only file system
 31 = Too many links
 32 = Broken pipe
 33 = Numerical argument out of domain
 34 = Result too large
 35 = Resource temporarily unavailable
 36 = Operation now in progress
 37 = Operation already in progress
 38 = Socket operation on non-socket
 39 = Destination address required
 40 = Message too long
 41 = Protocol wrong type for socket
 42 = Protocol not available
 43 = Protocol not supported
 44 = Socket type not supported
 45 = Operation not supported
 46 = Protocol family not supported
 47 = Address family not supported by protocol family
 48 = Address already in use
 49 = Can't assign requested address
 50 = Network is down
 51 = Network is unreachable
 52 = Network dropped connection on reset
 53 = Software caused connection abort
 54 = Connection reset by peer
 55 = No buffer space available
 56 = Socket is already connected
 57 = Socket is not connected
 58 = Can't send after socket shutdown
 59 = Too many references: can't splice
 60 = Operation timed out
 61 = Connection refused
 62 = Too many levels of symbolic links
 63 = File name too long
 64 = Host is down
 65 = No route to host
 66 = Directory not empty
 67 = Too many processes
 68 = Too many users
 69 = Disc quota exceeded
 70 = Stale NFS file handle
 71 = Too many levels of remote in path
 72 = RPC struct is bad
 73 = RPC version wrong
 74 = RPC prog. not avail
 75 = Program version wrong
 76 = Bad procedure for program
 77 = No locks available
 78 = Function not implemented
 79 = Inappropriate file type or format
 80 = Authentication error
 81 = Need authenticator
 82 = Device power is off
 83 = Device error
 84 = Value too large to be stored in data type
 85 = Bad executable (or shared library)
 86 = Bad CPU type in executable
 87 = Shared library version mismatch
 88 = Malformed Mach-o file
 89 = Operation canceled
 90 = Identifier removed
 91 = No message of desired type
 92 = Illegal byte sequence
 93 = Attribute not found
 94 = Bad message
 95 = EMULTIHOP (Reserved)
 96 = No message available on STREAM
 97 = ENOLINK (Reserved)
 98 = No STREAM resources
 99 = Not a STREAM
100 = Protocol error
101 = STREAM ioctl timeout
102 = Operation not supported on socket
103 = Policy not found
104 = State not recoverable
105 = Previous owner died
106 = Interface output queue is full

However, don’t use this array; it’s deprecated. You should instead use the strerror function:

#include <string.h>
char *strerror(int errnum);

So the modern way to print all errors is:

#include <stdio.h>
#include <string.h>
int main() {
  for (size_t i = 0; i < sys_nerr; i++) {
    printf("%*zu = %s\n", 3, i, strerror(i));
  }
}

I wrote this because I felt like it. This post is my own, and not associated with my employer.

Jim. Friends. Vidrio.