When a standard library function or system call fails, it tells you two things: the return value (NULL, -1, or similar) tells you that it failed, and errno.h tells you why. Without errno, you would know something went wrong but not whether the file did not exist, you lacked permission, or the disk was full. errno is the variable that carries that reason.
#include <errno.h> #include <stdio.h> #include <string.h> FILE *f = fopen("missing.txt", "r"); if (!f) { printf("error %d: %s\n", errno, strerror(errno)); // e.g.: error 2: No such file or directory }
strerror(errno) converts the code to a human-readable string. perror("label") does the same and prints directly to stderr with your prefix attached.
The most common codes:
EPERM 1 Operation not permitted ENOENT 2 No such file or directory EINTR 4 Interrupted by signal EACCES 13 Permission denied EEXIST 17 File already exists EINVAL 22 Invalid argument ENOSPC 28 No space left on device EAGAIN 11 Try again (resource temporarily unavailable) ERANGE 34 Result too large
One rule you must not break: only check errno immediately after a function that is documented to set it returns a failure indicator. A successful call is allowed to overwrite errno with any value, so checking it after a success gives you meaningless noise. Also, on any POSIX system errno is thread-local — a failure in another thread does not corrupt yours.
// compile: gcc -o errdemo errdemo.c // run: ./errdemo // description: trigger two different errno values and show strerror output #include <errno.h> #include <stdio.h> #include <string.h> int main(void) { FILE *f; f = fopen("/this/path/does/not/exist", "r"); if (!f) fprintf(stderr, "nonexistent: %s\n", strerror(errno)); f = fopen("/etc/shadow", "r"); if (!f) fprintf(stderr, "/etc/shadow: %s\n", strerror(errno)); // successful call; do NOT rely on errno after this f = fopen("/dev/null", "r"); if (f) { fclose(f); printf("opened /dev/null; errno is now %d (stale — ignore it)\n", errno); } return 0; }
The first call gives ENOENT, the second EACCES (or ENOENT if /etc/shadow does not exist on your system). The third call succeeds and the printed errno value is leftover from before — that is the point of the stale-value warning. When debugging errno-related code, always check it before any other library call, not several lines later.