C errno.h Library Reference
Complete reference for errno.h - error handling with errno, perror(), strerror(), and common error codes.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Check and handle errno
- ✓Use perror() and strerror()
- ✓Understand common error codes
- ✓Implement proper error handling
?Why Use errno.h?
C doesn't have exceptions like C++ or Java. When something fails, functions return -1 or NULL, but why did it fail? errno tells you!
File Errors
ENOENT, EACCES
Memory Errors
ENOMEM
Math Errors
ERANGE, EDOM
01Introduction to errno.h
What is errno.h?
<errno.h> provides the error reporting mechanismfor C programs. When library functions encounter errors, they set the errno variable to indicate what went wrong.
Key Components
| Name | Type | Description |
|---|---|---|
| errno | int (macro) | Error number set by system calls |
| perror() | Function | Print error message to stderr |
| strerror() | Function | Get error message string |
02The errno Variable
errno is a global variable (actually a macro that expands to a modifiable lvalue) that holds the error code from the last system call or library function that failed.
Important Rules:
- Always set
errno = 0before calling a function - Check errno only if the function indicates failure
- errno is never set to 0 by any standard library function
- errno may be changed by successful function calls
1#include <stdio.h>2#include <errno.h>3#include <math.h>4#include <string.h>56int main() {7 // Example 1: File open error8 errno = 0; // Clear errno before call9 FILE *fp = fopen("nonexistent_file.txt", "r");10 11 if (fp == NULL) {12 printf("Error opening file!\n");13 printf("errno value: %d\n", errno);14 printf("Error message: %s\n", strerror(errno));15 }16 17 // Example 2: Math error18 errno = 0;19 double result = sqrt(-1.0); // Invalid: sqrt of negative20 21 if (errno != 0) {22 printf("\nMath error occurred!\n");23 printf("errno value: %d\n", errno);24 printf("Error message: %s\n", strerror(errno));25 printf("Result: %f\n", result); // NaN26 }27 28 // Example 3: Number too large29 errno = 0;30 result = exp(1000); // Overflow31 32 if (errno == ERANGE) {33 printf("\nRange error: number too large!\n");34 printf("Error message: %s\n", strerror(errno));35 }36 37 return 0;38}3940/* Output:41Error opening file!42errno value: 243Error message: No such file or directory4445Math error occurred!46errno value: 3347Error message: Numerical argument out of domain48Result: nan4950Range error: number too large!51Error message: Numerical result out of range52*/03Common Error Codes
| Macro | Value | Description |
|---|---|---|
| EDOM | 33 | Math argument out of domain (e.g., sqrt(-1)) |
| ERANGE | 34 | Result out of range (overflow/underflow) |
| EILSEQ | 84 | Illegal byte sequence |
| ENOENT | 2 | No such file or directory |
| EACCES | 13 | Permission denied |
| ENOMEM | 12 | Out of memory |
| EEXIST | 17 | File already exists |
| EINVAL | 22 | Invalid argument |
| ENOSPC | 28 | No space left on device |
| EBADF | 9 | Bad file descriptor |
Note:
Error codes and their numeric values may vary between platforms. Always use the macro names (ENOENT, EACCES, etc.) instead of numeric values for portability.
04perror() - Print Error Message
void perror(const char *s);
perror() prints a custom message followed by a colon and the error message corresponding to the current value of errno. Output goes to stderr.
1#include <stdio.h>2#include <errno.h>34int main() {5 // Try to open a non-existent file6 FILE *fp = fopen("/nonexistent/path/file.txt", "r");7 8 if (fp == NULL) {9 // perror prints to stderr10 perror("Error opening file");11 12 // Equivalent manual approach:13 // fprintf(stderr, "Error opening file: %s\n", strerror(errno));14 }15 16 // Try to open a protected file (if on Unix-like system)17 fp = fopen("/etc/shadow", "r");18 19 if (fp == NULL) {20 perror("Cannot read shadow file");21 }22 23 // Empty string still prints error24 errno = ENOMEM;25 perror(""); // Just prints the error message26 27 // NULL prints just the error28 errno = EINVAL;29 perror(NULL);30 31 return 0;32}3334/* Output:35Error opening file: No such file or directory36Cannot read shadow file: Permission denied37: Cannot allocate memory38Invalid argument39*/05strerror() - Get Error String
char *strerror(int errnum);
strerror() returns a pointer to a string describing the error code passed as argument. More flexible than perror() as you can use the string however you want.
1#include <stdio.h>2#include <string.h>3#include <errno.h>45int main() {6 // Get error message for specific error codes7 printf("ENOENT (%d): %s\n", ENOENT, strerror(ENOENT));8 printf("EACCES (%d): %s\n", EACCES, strerror(EACCES));9 printf("ENOMEM (%d): %s\n", ENOMEM, strerror(ENOMEM));10 printf("EINVAL (%d): %s\n", EINVAL, strerror(EINVAL));11 printf("ERANGE (%d): %s\n", ERANGE, strerror(ERANGE));12 printf("EDOM (%d): %s\n", EDOM, strerror(EDOM));13 14 // Use with errno after an error15 FILE *fp = fopen("nonexistent.txt", "r");16 if (fp == NULL) {17 // Store errno immediately - it might change18 int saved_errno = errno;19 20 // Now use it21 printf("\nFile open failed: %s (errno=%d)\n", 22 strerror(saved_errno), saved_errno);23 }24 25 // Custom error logging function26 printf("\n--- Custom Error Log ---\n");27 errno = 0;28 fp = fopen("/root/secret.txt", "r");29 if (fp == NULL) {30 fprintf(stderr, "[ERROR] %s:%d: Failed to open file: %s\n",31 __FILE__, __LINE__, strerror(errno));32 }33 34 return 0;35}3637/* Output:38ENOENT (2): No such file or directory39EACCES (13): Permission denied40ENOMEM (12): Cannot allocate memory41EINVAL (22): Invalid argument42ERANGE (34): Numerical result out of range43EDOM (33): Numerical argument out of domain4445File open failed: No such file or directory (errno=2)4647--- Custom Error Log ---48[ERROR] example.c:35: Failed to open file: Permission denied49*/Thread Safety:
strerror() may return a pointer to a static buffer, making it not thread-safe. Use strerror_r() (POSIX) or strerror_s() (C11) in multi-threaded programs.
06Error Handling Best Practices
1#include <stdio.h>2#include <stdlib.h>3#include <string.h>4#include <errno.h>56// Good error handling pattern7FILE *safe_fopen(const char *path, const char *mode) {8 errno = 0; // Clear errno before call9 10 FILE *fp = fopen(path, mode);11 12 if (fp == NULL) {13 // Save errno immediately14 int err = errno;15 16 // Log detailed error17 fprintf(stderr, "Error: Cannot open '%s' (mode '%s'): %s\n",18 path, mode, strerror(err));19 20 return NULL;21 }22 23 return fp;24}2526// Safe string to number conversion27long safe_strtol(const char *str, int *error) {28 char *endptr;29 errno = 0; // Clear errno30 31 long val = strtol(str, &endptr, 10);32 33 // Check for errors34 if (errno == ERANGE) {35 *error = 1;36 fprintf(stderr, "Error: Number out of range: %s\n", str);37 return 0;38 }39 40 if (endptr == str) {41 *error = 2;42 fprintf(stderr, "Error: No digits found in: %s\n", str);43 return 0;44 }45 46 if (*endptr != '\0') {47 *error = 3;48 fprintf(stderr, "Warning: Extra characters after number: %s\n", endptr);49 }50 51 *error = 0;52 return val;53}5455int main() {56 // Test safe_fopen57 FILE *fp = safe_fopen("test.txt", "r");58 if (fp) {59 printf("File opened successfully\n");60 fclose(fp);61 }62 63 // Test safe_strtol64 int error;65 const char *tests[] = {"42", "9999999999999999999", "abc", "123abc"};66 67 printf("\n--- String to Long Conversion ---\n");68 for (int i = 0; i < 4; i++) {69 long val = safe_strtol(tests[i], &error);70 if (error == 0) {71 printf("'%s' -> %ld\n", tests[i], val);72 }73 }74 75 return 0;76}7778/* Output:79Error: Cannot open 'test.txt' (mode 'r'): No such file or directory8081--- String to Long Conversion ---82'42' -> 4283Error: Number out of range: 999999999999999999984Error: No digits found in: abc85Warning: Extra characters after number: abc86'123abc' -> 12387*/!Code Pitfalls: Common Mistakes & What to Watch For
Copied code rarely checks errno properly, leading to silent failures that are hard to debug.
If you search online to "read a file and parse numbers," it will likely use fopen(), strtol(), and other functions without checking errno. When these fail (file not found, invalid number, overflow), the copied code continues with garbage values instead of handling the error.
The Trap: Online sources produce "happy path" code that assumes everything succeeds. They often forget to: (1) set errno to 0 before the call, (2) check the return value, (3) check errno immediately after, and (4) use perror() or strerror() for meaningful error messages.
The Reality: Robust C code must check for errors after every operation that can fail. Always follow the pattern: set errno = 0, call the function, check return value and errno, handle errors appropriately. This is tedious but essential — beginners skip it, you shouldn't.
08Frequently Asked Questions
Q:Why should I check errno immediately after a function call?
A: Because errno can be overwritten by the next function call, even if it succeeds! Save it to a local variable immediately: int err = errno;
Q:What's the difference between perror() and strerror()?
A: perror() prints directly to stderr with your prefix. strerror() returns a string you can format yourself, store, or log. Use perror for quick debugging, strerror for custom error handling.
Q:Why should I set errno = 0 before calling a function?
A: Some functions don't modify errno on success. If errno already had a non-zero value from an earlier error, you might mistake it for a new error. Clear it first to be safe.
Q:Is errno thread-safe?
A: Yes, in modern C (C11+) and POSIX systems! Each thread has its own errno. However,strerror() may not be thread-safe — usestrerror_r() in multi-threaded code.
08Quick Reference
Error Checking Pattern
errno = 0; // Clearresult = function(); // Callif (result == ERROR) { int err = errno; // Save handle_error(err);}Functions
perror(msg)- Print to stderrstrerror(errno)- Get error string
stddef.h Library
Next →assert.h Library
Test Your Knowledge
Related Tutorials
C stddef.h Library Reference
Complete reference for stddef.h - NULL, size_t, ptrdiff_t, offsetof, and fundamental type definitions.
C assert.h Library Reference
Complete reference for assert.h - runtime assertions, NDEBUG, static_assert (C11), and debugging best practices.
C stdint.h Library Reference
Complete reference for stdint.h - fixed-width integers (int8_t, int32_t), limit macros, and portable integer code.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!