The <errno.h> header defines errno, a shared error indicator that many C library functions set when something goes wrong. Combined with return-value checks and helpers like perror and strerror, it lets your program report failures clearly instead of crashing silently.
01
errno
Error code.
02
EDOM
Bad input.
03
ERANGE
Overflow.
04
perror
Print error.
05
Reset
errno = 0.
06
Return
Check first.
Fundamentals
Definition and Usage
errno is a macro that expands to a modifiable int lvalue. When a library function fails, it often stores a positive error code in errno so your program can tell why it failed. At program startup, errno is zero.
Crucially, library functions do not clearerrno on success. A leftover value from an earlier error can mislead you if you read errno without checking the function’s return value or without resetting errno before the call.
💡
Beginner Tip
The safe pattern is: check the return value first (e.g. if (fp == NULL)), then read errno. For functions like strtol, set errno = 0 immediately before the call.
Foundation
📝 Syntax
Include the header:
C
#include <errno.h>
The errno macro
Portable code uses errno directly after including the header. You do not need to write extern int errno; yourself.
C
errno = 0; /* reset before a call when needed */
if (some_call() fails) {
if (errno != 0) { /* inspect error code */
/* handle error */
}
}
Common error macros (errno.h)
EDOM — domain error (invalid argument to a math function, e.g. sqrt(-1)).
ERANGE — range error (result too large or too small to represent).
EINVAL — invalid argument (common on POSIX systems).
EINTR — interrupted system call (POSIX).
ENOMEM — not enough memory (POSIX).
Additional codes like ENOENT (“No such file or directory”) come from the host system and are used by functions such as fopen.
Related helpers (other headers)
perror(const char *s) — prints s plus error message to stderr (<stdio.h>).
strerror(int errnum) — returns a string for error code errnum (<string.h>).
Headers and linking
#include <errno.h> for errno, EDOM, ERANGE.
#include <stdio.h> for perror; #include <string.h> for strerror.
Math examples: gcc program.c -std=c11 -lm -o program
Cheat Sheet
⚡ Quick Reference
Symbol
Meaning
Typical use
errno
Last error code
Read after failed call
EDOM
Domain error
sqrt(-1), invalid math input
ERANGE
Range error
Overflow in strtol, huge exp
perror("msg")
Print to stderr
perror("fopen")
strerror(errno)
Error string
printf("%s", strerror(errno))
Reset
errno = 0;
Before strtol
File I/O
if (fp == NULL)
Then read errno
perror
perror("open");
Quick debug
strerror
strerror(errno)
Custom format
Hands-On
Examples Gallery
Compile with gcc file.c -std=c11 -o out. Add -lm for math examples. Always check return values; use errno to learn why a documented failure happened.
📚 Getting Started
Report file and math errors with errno, perror, and strerror.
Example 1 — Open a Missing File with strerror
Classic pattern from the reference: fopen returns NULL on failure and sets errno.
Error opening file: No such file or directory (errno=2)
How It Works
fopen fails because the file does not exist. We check file == NULL first, then use strerror(errno) for a readable message. On Linux, errno 2 is typically ENOENT.
Example 2 — Math Domain Error with perror
sqrt(-1) is invalid; errno is set to EDOM. Link with -lm.
sqrt(-1) = nan
sqrt domain error: Numerical argument out of domain
How It Works
We reset errno before sqrt so we know the error came from this call. The function still returns NaN; checking errno == EDOM confirms a domain error. perror prints to stderr with a colon and the system message.
📈 Practical Patterns
Parsing, comparing error helpers, and the reset-before-call idiom.
Example 3 — Detect Overflow with strtol and ERANGE
strtol returns a value even on failure—you must reset errno and check it.
C
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
const char *big = "999999999999999999999";
char *end = NULL;
long value;
errno = 0;
value = strtol(big, &end, 10);
if (errno == ERANGE) {
printf("Overflow: value out of long range\n");
} else if (end == big) {
printf("No digits parsed\n");
} else {
printf("Parsed: %ld\n", value);
}
return 0;
}
📤 Output:
Overflow: value out of long range
How It Works
Without errno = 0 first, a stale errno could falsely suggest overflow. ERANGE means the numeric result cannot fit in a long. Also check end to detect invalid input.
Example 4 — perror vs strerror Side by Side
Two ways to show the same file-not-found error.
C
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void) {
if (fopen("missing.dat", "r") == NULL) {
perror("perror says"); /* to stderr */
printf("strerror says: %s\n", strerror(errno)); /* to stdout */
}
return 0;
}
📤 Output:
perror says: No such file or directory
strerror says: No such file or directory
How It Works
perror adds your prefix and a newline on stderr—ideal for quick debugging. strerror gives you a string to format in logs or GUI messages. Both read the current errno.
Example 5 — Why You Must Reset errno
Demonstrates how a leftover errno causes a false alarm if you skip the reset.
C
#include <errno.h>
#include <stdio.h>
#include <string.h>
int main(void) {
/* Simulate an earlier error */
errno = EDOM;
/* Successful call — does NOT clear errno */
char msg[] = "hello";
size_t len = strlen(msg);
printf("strlen = %zu\n", len);
if (errno != 0) {
printf("False alarm: errno is still %d (%s)\n",
errno, strerror(errno));
}
/* Correct approach for the next operation */
errno = 0;
len = strlen(msg);
if (errno != 0) {
printf("strlen failed?\n");
} else {
printf("After reset: errno is 0 (correct)\n");
}
return 0;
}
📤 Output:
strlen = 5
False alarm: errno is still 33 (Numerical argument out of domain)
After reset: errno is 0 (correct)
How It Works
strlen never touches errno, but the old EDOM value remains. This is why you check return values for functions that signal failure that way, and reset errno only when the function you are about to call documents errno usage.
Applications
🚀 Common Use Cases
File I/O — report why fopen, read, or fwrite failed.
String-to-number parsing — detect overflow and invalid input with strtol/strtod.
Math libraries — catch EDOM and ERANGE from sqrt, log, exp.
CLI tools — print friendly errors with perror when system calls fail.
Logging — store strerror(errno) in log files with timestamps.
Defensive libraries — document which error codes your wrapper sets for callers.
🧠 How errno.h Works
1
Call library function
Optionally set errno = 0 first if the function uses errno on failure.
Invoke
2
Check return value
NULL, -1, EOF, or NaN—each function documents its failure signal.
Validate
3
Read errno
If failure, errno holds a positive code (e.g. EDOM, ENOENT).
Inspect
=
💬
Report or recover
Use perror, strerror, or branch on specific codes.
Important
📝 Notes
errno is a macro, not a normal global variable you declare yourself.
Since C11, errno is thread-local—each thread has its own value.
Successful calls may leave errno unchanged; never assume it is zero after success.
Only read errno immediately after a failed call—other calls may overwrite it.
strerror returns a pointer to a static buffer; it may be overwritten by the next strerror call.
Math functions may also set the floating-point exception flags; errno is one part of error reporting.
Performance
⚡ Optimization
Reading and setting errno is negligible overhead. In release builds, focus on correct error paths rather than avoiding errno. For hot paths, still check return values; skip string formatting (perror/strerror) unless you actually report the error.
Wrap Up
Conclusion
<errno.h> is the standard way C programs learn why a library call failed. Combine return-value checks with errno, reset before calls when required, and use perror or strerror for human-readable messages.
For development-time bugs, use <assert.h>; for real runtime failures users might trigger, use errno and proper error handling.
Write extern int errno; instead of including the header
Ignore return values and rely only on errno
Compare errno after unrelated function calls
Use assert for expected user errors (files missing, bad input)
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about errno.h
Error handling in C, explained simply.
5
Core concepts
💬01
errno
Error code.
Basics
📚02
Return
Check first.
Pattern
📈03
Reset
errno = 0.
Safety
📄04
EDOM
Bad input.
Math
🌐05
perror
Print msg.
Report
❓ Frequently Asked Questions
errno.h declares the errno macro—a modifiable int lvalue that library functions set when they fail. It also defines error code macros like EDOM and ERANGE. Include it with #include <errno.h> whenever you inspect or reset errno.
errno is a macro that expands to an lvalue (often thread-local since C11). You do not declare extern int errno yourself in portable code; just #include <errno.h> and use errno directly.
Set errno = 0 immediately before a call when you need to know whether that specific call failed—especially for functions like strtol() that return a value on both success and failure. Many functions only set errno on error and leave it unchanged on success.
perror(msg) prints your message plus a system error string for the current errno to stderr. strerror(errno) returns a pointer to a human-readable string you can pass to printf. perror needs <stdio.h>; strerror needs <string.h>.
No. Always check the function's return value first (NULL, -1, EOF, etc.). Only some functions document that they set errno on failure—fopen, strtol, and many math functions do; others may not touch errno at all.
EDOM means a domain error (invalid input to a math function, e.g. sqrt(-1)). ERANGE means a range error (result too large, e.g. overflow in strtod). Both are macros defined in errno.h with positive integer values.
Did you know?
Before standardized errno, Unix programs each invented their own error reporting. Today errno is specified in C and is thread-local in modern implementations—but the habit of checking return values first is still essential, because not every failed function sets errno, and successful calls never guarantee it is zero.