errno.h
<errno.h> is a header file in the C standard library that declares the modifiable integer variable errno, a thread-local (since C11) lvalue initialized to 0 at program startup, which system calls and library functions set to positive integer values to report errors upon failure.[1] It also defines symbolic constants for these error codes, providing unique positive integers for conditions such as EDOM (domain error), ERANGE (range error), and EILSEQ (illegal byte sequence), as required by the ISO C standard, with additional constants mandated by POSIX for system-specific errors like EACCES (permission denied) and ENOENT (no such file or directory).[2][1]
The errno mechanism ensures that error information is preserved across function calls, though its value should be checked and saved immediately after a failing operation, as subsequent library calls may overwrite it.[3] Defined since the original C89 standard and extended in later revisions like C99 and C11, <errno.h> facilitates portable error handling in C programs by standardizing error reporting across compliant systems, while allowing implementations to include platform-specific extensions.[1] In POSIX environments, the header guarantees at least 60 distinct error constants, with values that must remain unique except in cases like EAGAIN and EWOULDBLOCK, which may alias each other.[2] Functions like perror() and strerror() from the same library use these codes to provide human-readable error messages.[1]
Overview
Definition and Purpose
The<errno.h> header file is a standard component of the C programming language library, providing a macro for the symbol errno, which expands to a modifiable lvalue of type int and defining macros that represent distinct positive error numbers, typically prefixed with E (such as EDOM or ERANGE).[4] These macros encode specific error conditions encountered during program execution, enabling standardized identification of failures across compliant systems.[4]
The primary purpose of <errno.h> is to facilitate portable error reporting in system calls and library functions, where a function's return value (often -1 or NULL) signals failure, but the precise reason is stored separately in errno rather than being returned directly.[3] This design allows functions to distinguish between valid negative or null results and error states without ambiguity, promoting consistency in error handling across different implementations of the C standard.[3]
In operation, errno is set to a non-zero value by qualifying functions upon detecting an error, while successful calls do not set it to 0 and may either leave it unchanged or set it to another non-zero value.[3] Notably, errno is not a function but expands to a modifiable lvalue of type int, permitting direct assignment and inspection by the programmer; in modern implementations conforming to C11 and POSIX, it employs thread-local storage to ensure isolation of error states across concurrent threads.[1][4]
Standards Compliance
Theerrno.h header is included in the ISO C standards starting from C89 (ISO/IEC 9899:1990), where it requires a declaration or definition for the symbol errno, which expands to a modifiable lvalue of type int, along with at least two specific error code macros: EDOM for domain errors (e.g., invalid arguments to mathematical functions) and ERANGE for range errors (e.g., overflow or underflow in computations).[5] These macros must expand to distinct positive integer constant expressions, ensuring they do not overlap with zero or each other, to facilitate portable error checking across implementations.[4] The C89 standard focuses on error reporting for library functions in headers like <math.h> and <stdlib.h>, without specifying thread-related behaviors.[5]
POSIX.1 compliance, as defined by IEEE Std 1003.1, extends these requirements significantly for system interfaces, mandating errno as a thread-specific value—meaning each thread in a process maintains its own independent copy, unaffected by operations in other threads—and a minimum set of over 30 error code macros, including core ones like EACCES (permission denied), ENOENT (no such file or directory), EBADF (bad file descriptor), and EINVAL (invalid argument).[4][6] These POSIX macros also expand to distinct positive integers, with the standard prohibiting any function from setting errno to zero and requiring that its value only be examined after a function indicates an error via its return value.[4] This ensures reliable error propagation in multi-threaded environments on compliant systems.
The standards have evolved to enhance portability and safety: C99 (ISO/IEC 9899:1999) explicitly requires errno to be a modifiable lvalue, allowing programs to inspect and potentially reset it after error checks, while adding the EILSEQ macro for invalid multibyte sequences.[4] POSIX.1-2008 (IEEE Std 1003.1-2008) further strengthens thread-safety guarantees by clarifying that all specified functions are thread-safe unless exempted, with errno treated as thread-local to prevent race conditions, and introducing additional macros like ENOTRECOVERABLE and EOWNERDEAD for robust mutex handling.[4][6] These updates align POSIX with contemporary ISO C revisions, promoting consistent behavior across Unix-like and other compliant platforms without mandating specific numeric values for the macros, only their distinctiveness.[4]
Error Handling Fundamentals
The errno Variable
Theerrno variable is declared in the <errno.h> header as an external integer modifiable lvalue, accessible only after including the header to define associated macros.[4] Programs must include <errno.h> to use errno alongside the symbolic error constants it references.[3]
Upon failure, library functions and system calls set errno to a non-zero value representing the specific error condition, such as fopen assigning ENOENT when a file is not found.[7] This value must be inspected immediately after the function returns an error indicator, as subsequent calls to other functions may overwrite errno with their own error states if they fail.[1] The variable initializes to 0 at program startup, and no standard library function ever resets it to 0; thus, a non-zero value after a failed call signals an error identifiable through the E* macros defined in <errno.h>.
For thread safety in multi-threaded environments using POSIX threads (pthreads), each thread maintains its own instance of errno since the POSIX.1-2001 standard, ensuring that modifications in one thread do not affect others.[8] To achieve this, errno is often implemented not as a simple global variable but as a macro that expands to a function call retrieving thread-local storage, such as (*__errno_location()) in GNU/Linux systems.[9] This design enhances portability across thread-aware implementations while preserving the interface's semantics.[4]
Error Code Macros
The error code macros in<errno.h> are symbolic constants, typically prefixed with E (such as EPERM and ENOENT), that represent distinct error conditions encountered during program execution. These macros expand to integer constant expressions of type int, each evaluating to a unique positive integer value greater than or equal to 1, ensuring no overlaps in their numerical representations across compliant implementations. This design allows for clear identification of specific errors without relying on platform-dependent numeric codes, providing a standardized abstraction layer over underlying system error numbers.[4][10]
The International Organization for Standardization (ISO) C standard mandates a minimal core set of these macros to support error reporting in mathematical functions and other library operations. Specifically, EDOM indicates a domain error (e.g., invalid argument to a function like sqrt(-1)), ERANGE signals a result out of range (e.g., overflow in exp()), and EILSEQ denotes an invalid or incomplete multibyte sequence, as added in the C99 revision. POSIX.1 extends this requirement significantly, mandating a broader collection of macros for system calls and library functions, including examples like EBADF for bad file descriptors; however, certain STREAMS-related macros (e.g., ENODATA) are optional and considered obsolescent in modern POSIX revisions. Implementations may also define additional non-standard macros, such as EWOULDBLOCK for non-blocking operations that would block, which on some systems aliases to EAGAIN but maintains distinct semantics for portability.[4][10][11]
In practice, programmers use these macros to check the value of the errno variable after a function call that may fail, promoting code portability across different systems. For instance, after an unsuccessful file open operation, one might test if (errno == ENOENT) to handle the "no such file or directory" condition, rather than comparing against a hardcoded integer like 2, which could vary by platform. This approach leverages the macros' expansion to int expressions, enabling their use in conditional statements, switches, or preprocessing directives while avoiding direct numeric dependencies. By encapsulating error numbers in named symbols, the macros facilitate readable, maintainable code that adheres to standards without exposing implementation details.[4][3]
POSIX Error Codes
Core POSIX Errors
The core POSIX error codes form a foundational set of over 60 macros defined in the<errno.h> header, representing essential error conditions for system calls and library functions in POSIX-compliant environments. These macros expand to unique positive integer values, though the specific numeric assignments are implementation-defined to allow flexibility across systems. They enable portable error reporting, ensuring that applications can detect and handle failures consistently without relying on platform-specific details. The following table enumerates selected common core POSIX error codes, providing a brief description of each and typical causes or triggers, often arising in file operations, process management, or resource allocation. For a complete list, refer to the POSIX standard.[4]
The following table enumerates selected common POSIX error codes, providing a brief description of each and typical causes or triggers, often arising in file operations, process management, or resource allocation.
| Code | Description | Common Triggers |
|---|---|---|
| EPERM | Operation not permitted | Attempting to perform a privileged operation, such as changing file ownership without root privileges, in functions like chmod().[4][3] |
| ENOENT | No such file or directory | Specifying a nonexistent pathname in open() or stat(), where the file or directory path does not exist.[4][3] |
| ESRCH | No such process | Searching for a process ID that does not exist, as in kill() or waitpid() when the PID is invalid.[4][3] |
| EINTR | Interrupted function | A system call like read() or wait() being interrupted by a signal before completion.[4][3] |
| EIO | I/O error | Low-level input/output failure during disk or device operations, such as in read() on a failing hardware device.[4][3] |
| ENOEXEC | Executable format error | Loading an executable file with an invalid or unsupported format via execve().[4][3] |
| EBADF | Bad file descriptor | Using an invalid or closed file descriptor in read() or close().[4][3] |
| ECHILD | No child processes | Calling wait() when no child processes exist or have already been reaped.[4][3] |
| EAGAIN | Resource temporarily unavailable | Attempting a non-blocking operation like read() when no data is available immediately, often requiring retry.[4][3] |
| ENOMEM | Not enough space | Allocation failure due to insufficient memory or other resources in malloc() or fork().[4][3] |
| EACCES | Permission denied | Accessing a file or directory without read/write permissions via open() or access().[4][3] |
| EFAULT | Bad address | Passing an invalid memory address to a system call like read() or write().[4][3] |
| EBUSY | Device or resource busy | Attempting to unmount a filesystem that is in use or remounting a busy device.[4][3] |
| EEXIST | File exists | Trying to create a file or directory that already exists with open() using O_CREAT |
| EXDEV | Cross-device link | Creating a hard link between files on different filesystems via link().[4][3] |
| ENODEV | No such device | Referencing a device that does not exist in the system, such as in mount operations.[4][3] |
| ENOTDIR | Not a directory | Treating a non-directory file as a directory in chdir() or path traversal.[4][3] |
| EISDIR | Is a directory | Attempting to open a directory as a regular file with open() in read/write mode.[4][3] |
| EINVAL | Invalid argument | Passing an inappropriate or out-of-range argument to a function like lseek().[4][3] |
| ENFILE | Too many files open in system | Exceeding the system-wide limit on open files during open().[4][3] |
| EMFILE | Too many open files | Surpassing the per-process limit on open file descriptors in open().[4][3] |
| ENOTTY | Inappropriate I/O control operation | Using ioctl() on a file descriptor not associated with a terminal or suitable device.[4][3] |
| ETXTBSY | Text file busy | Attempting to write to or execute a file that is currently being executed by another process.[4][3] |
| EFBIG | File too large | Writing beyond the maximum file size limit in write().[4][3] |
| ENOSPC | No space left on device | Disk full during write() or file creation operations.[4][3] |
| ESPIPE | Invalid seek | Seeking on a pipe or socket with lseek(), where positioning is not supported.[4][3] |
| EROFS | Read-only file system | Attempting to write or modify a file on a read-only mounted filesystem.[4][3] |
| EMLINK | Too many links | Creating a hard link that would exceed the maximum number allowed per file.[4][3] |
| EPIPE | Broken pipe | Writing to a pipe after the reading end has been closed, often in write().[4][3] |
Usage in System Calls
In POSIX-compliant systems, system calls such asread(), write(), and open() follow a standard error-reporting pattern: upon failure, they return -1 and set the global errno variable to an appropriate positive error code macro defined in <errno.h>, such as EACCES or EINVAL.[4] This mechanism provides detailed diagnostics beyond a mere success/failure indication, enabling developers to implement targeted error recovery strategies in robust applications.[4] By distinguishing between various failure modes—ranging from permission denials to resource shortages—errno supports precise handling of exceptional conditions in system-level programming.[4]
POSIX.1 mandates that all failing system calls set errno to one of the defined error codes unless explicitly documented otherwise, ensuring consistent behavior across compliant implementations.[4] For instance, the fork() system call returns -1 on failure and sets errno to EAGAIN if insufficient resources prevent process creation, such as when system-imposed limits on processes or threads are reached.[12] Similarly, mkdir() returns -1 and sets errno to EEXIST if the specified directory already exists, preventing accidental overwrites or conflicts.[13] These examples illustrate how errno integrates directly with system call semantics to convey specific failure reasons, facilitating debugging and resilience in POSIX environments.[14]
Best practices for using errno with system calls emphasize checking the return value first: only inspect errno if the call returns -1, as its value is undefined or irrelevant on success and may be altered by intervening operations. This approach avoids false positives, since successful calls do not reset or guarantee the preservation of prior errno values.[4] Note that while system calls reliably set errno on failure, some library functions like printf() do not set it even on error, relying instead on their return value (e.g., a negative count) for failure indication.[15] Adhering to this protocol ensures accurate error detection and prevents misinterpretation in multi-step operations.
Platform Variations
Unix-like Implementations
In Unix-like operating systems, the errno.h header file provides a standardized interface for error reporting through the errno variable and associated macros, with implementations that adhere closely to POSIX specifications while incorporating platform-specific extensions. These systems, including Linux and BSD variants, define errno as a thread-local variable to support multithreaded environments, ensuring that error codes set by system calls are accessible per thread without interference. The header typically includes all core POSIX error codes, such as ENOENT (value 2, indicating "no such file or directory") and EACCES (value 13, for "permission denied"), which originated from early Unix designs and were formalized in standards like POSIX.1-1988. Note that while symbolic constants are standardized, their numeric values are implementation-defined and may vary across systems.[4] In Linux, the errno.h header is provided by the GNU C Library (glibc), where errno is implemented as a macro expanding to a call to the function __errno_location(), which returns a pointer to the thread-local errno storage. This approach allows glibc to manage errno efficiently in multithreaded applications using the Native POSIX Thread Library (NPTL). Beyond POSIX-required codes, Linux extends errno.h with kernel-specific errors, such as ENETRESET (value 102, indicating "Network dropped connection because of reset") and EHWPOISON (value 133, for hardware memory corruption detected by the kernel). These extensions are documented in the Linux man pages and reflect the operating system's integration of advanced networking and hardware features.[3] BSD-derived systems, such as FreeBSD, implement errno.h in a manner similar to Linux but with distinct extensions tailored to their kernel architecture. In FreeBSD, errno is implemented as a thread-local variable using the system's TLS facilities to maintain isolation across concurrent executions. FreeBSD's errno.h includes POSIX codes plus BSD-specific ones like ENOATTR (value 87, indicating "attribute not found") and EOPNOTSUPP (value 45, for "operation not supported on socket"), the latter being a common Unix extension not mandated by strict POSIX but widely adopted for socket and filesystem operations. These implementations ensure compatibility with POSIX while accommodating BSD's emphasis on networking and security features.[16] Traditional Unix variants, such as System V Release 4, established the numeric values for many errno codes that continue to influence modern Unix-like systems, with ENOENT consistently defined as 2 since the 1970s to enable portable error checking across utilities and libraries. Some Unix-like systems further integrate signals with errno for asynchronous error handling; for instance, writing to a pipe after the reader has closed it sets errno to EPIPE (value 32) and generates a SIGPIPE signal, which can terminate the process unless explicitly ignored or handled. This combination enhances robustness in networked and interprocess communication scenarios common to Unix environments.Non-POSIX Extensions
In environments like Windows, compatibility layers such as MinGW and Cygwin provide POSIX-compliant errno.h implementations by mapping standard POSIX error codes to underlying Windows error values returned by functions like GetLastError. For instance, the POSIX code ENOENT (value 2, indicating "No such file or directory") directly corresponds to the Windows error ERROR_FILE_NOT_FOUND (also 2), while socket-related errors like EADDRINUSE (value 98, "Address already in use") are derived from Winsock equivalents such as WSAEADDRINUSE (10048). These mappings ensure that POSIX applications can run with familiar error semantics, though internal translations may introduce subtle behavioral differences from native Unix systems.[17] Beyond core POSIX definitions, various platforms introduce additional error macros in errno.h to address system-specific conditions. On macOS, which builds on BSD foundations, ENOTSUP (value 45, "Operation not supported") is defined as an extension distinct from the POSIX-required EOPNOTSUPP, providing a finer-grained indication for unsupported operations in certain kernel interfaces. In embedded systems using lightweight C libraries like Newlib, rarely used or hardware-irrelevant codes—such as ECHRNG (44, "Channel number out of range," a legacy Linux-specific error for obsolete peripherals)—may be omitted to reduce footprint and simplify porting to resource-constrained devices without POSIX full compliance.[4] Compatibility layers like Wine, which enable POSIX applications to execute on Windows, perform bidirectional error translation by converting Windows NT status codes or GetLastError values into equivalent errno settings for POSIX system calls, ensuring seamless error propagation in emulated environments. The ISO C standard permits implementations to define additional E-prefixed macros beyond the required EDOM, EILSEQ, and ERANGE, provided they expand to unique positive integer constants to avoid conflicts with standard ones. Some non-POSIX systems, particularly certain microkernels or custom embedded runtimes, deviate by using negative values for errno to mimic kernel syscall conventions in user space, though this conflicts with the positive-value requirement in ISO C and POSIX.[18] These non-standard extensions and variations create portability challenges, often necessitating conditional compilation directives such as #ifdef _WIN32 or #ifdef APPLE to select platform-appropriate error handling code and avoid compilation errors from undefined macros.[4]Historical Context
Origins in Early Unix
Theerrno.h header file originated in Version 7 Unix, released in 1979 by researchers at Bell Laboratories, where it was introduced to standardize error reporting mechanisms within the C programming libraries. This development marked a significant step toward consistent handling of system call failures, allowing programmers to access predefined error codes as macros rather than relying on scattered numeric constants. By encapsulating error definitions in a dedicated header, it facilitated more reliable and portable code across Unix applications.[19][20]
Prior to Version 7, earlier iterations of Unix, such as Version 6 released in 1975, employed ad-hoc error returns from system calls, where failures typically yielded -1 or an invalid value without a unified framework for interpretation. While the errno variable existed as an external integer to capture error numbers in C programs—set only upon failure and left unchanged on success—the absence of a formal header meant error codes were not systematically defined or included, leading to inconsistencies in library usage. The formalization in errno.h established a global error state that improved debugging and maintainability.[21][22]
Ken Thompson and Dennis Ritchie, principal architects of Unix and the C language, played key roles in integrating errno.h into the C standard library, emphasizing portability for applications running on PDP-11 systems and beyond. Their efforts ensured that error reporting aligned with the growing ecosystem of Unix tools, drawing on the evolving C preprocessor to define symbolic constants. The original errno.h in Version 7 defined 34 error codes, from EPERM (1, operation not permitted) to ERANGE (34, result too large), covering common system and mathematical errors.[20]
Early implementations of errno, including in Version 7, were inherently limited by Unix's single-process model, assuming a global variable accessible only within one execution context and lacking provisions for concurrency. This design was not thread-safe, as concurrent access in later multi-threaded environments could lead to race conditions overwriting the error state; such issues were addressed in subsequent standards through per-thread storage.[20][3]
Standardization Process
The standardization of errno.h began with its formal inclusion in the ANSI C standard, designated as X3.159-1989, which was published in December 1989. This standard required the declaration of the errno variable as a modifiable lvalue of type int and defined basic error macros, primarily EDOM and ERANGE, to handle domain and range errors in mathematical functions from <math.h>. These provisions ensured that library functions could report errors consistently without relying on return value conventions alone, marking the first portable specification for error reporting in C programs across diverse implementations.[5] The POSIX standards further expanded and formalized errno.h for Unix-like systems. In POSIX.1-1990 (IEEE Std 1003.1-1990, also ISO/IEC 9945-1:1990), a comprehensive set of error codes was mandated for system interfaces, building on the ANSI C foundation to include symbols like EPERM, ENOENT, and EACCES for common file and process operations. By POSIX.1-2001 (IEEE Std 1003.1-2001), the requirement grew to over 50 distinct error codes, ensuring interoperability among conforming systems while allowing implementation-defined extensions. This adoption harmonized variations among Unix variants, with the POSIX working group in 1988 playing a pivotal role in reconciling differences from systems like BSD and System V.[23] Subsequent ISO C standards refined these aspects without major overhauls. The C99 standard (ISO/IEC 9899:1999) reinforced recommendations for thread-safety in errno access, suggesting implementations treat it as a macro expanding to thread-local storage to avoid race conditions in multithreaded environments. The C11 standard (ISO/IEC 9899:2011) introduced no significant changes to the error macros but explicitly clarified that errno must be an lvalue modifiable by library functions, aligning closely with POSIX requirements. A notable update occurred in the 2008 POSIX revision (IEEE Std 1003.1-2008), which incorporated real-time extensions and additional error codes like EOWNERDEAD for enhanced support in embedded and concurrent systems. Through these standardization efforts, errno.h achieved broad portability, enabling developers to write error-handling code that functions consistently across platforms. Today, while POSIX mandates a core set, variants like Linux extend to over 100 possible error codes, including platform-specific ones such as ENOSYS for unimplemented operations, without breaking conformance.[3]Practical Usage
Accessing and Interpreting Errors
In POSIX-compliant systems, programmers access theerrno value immediately following a library function or system call that returns an error indicator, typically -1 or NULL, to determine the specific error condition. The standard access pattern involves including the <errno.h> header to access the errno macro, which expands to a modifiable integer lvalue, and then checking its value conditionally, such as if (some_function() == -1) { if (errno == ENOENT) { /* handle no such file [error](/page/Error) */ } }. This ensures that errno is examined only when an error has occurred, as its value is unspecified or irrelevant after successful calls. Applications should set errno to 0 prior to invoking a function known to potentially set it, and inspect it solely after the function indicates failure, to avoid misinterpretation from prior or extraneous modifications.[24][4][3]
To interpret the numeric errno value into a human-readable form, the strerror() function from <string.h> is used, which maps the provided error number—commonly errno—to a locale-dependent string describing the error. For instance, strerror(ENOENT) typically yields a message such as "No such file or directory," though the exact wording is implementation-defined and may vary by locale. The returned pointer points to a static string that should not be modified and may be overwritten by subsequent calls to strerror() or related functions. For diagnostic output, the perror() function from <stdio.h> combines a user-supplied prefix string with the error message derived from errno via an internal call to strerror(), printing the result to standard error followed by a newline; an example usage is perror("open failed"), which might output "open failed: No such file or directory". Both functions facilitate debugging without requiring manual mapping of error codes.[25][26][27]
Best practices emphasize preserving the errno value promptly after detection to prevent loss due to intervening function calls that might alter it, such as by assigning it to a local variable: int saved_errno = errno;. Programmers must avoid assuming or checking errno after successful operations, as it may be modified unpredictably, and should never rely on its value without an accompanying error return code. Notably, not all POSIX functions employ errno for error reporting; for example, getaddrinfo() from <netdb.h> returns its own error codes (e.g., EAI_NONAME) and uses gai_strerror() for interpretation, resorting to errno only in the EAI_SYSTEM case.[3][28]
Multithreading and Thread-Safety
In multithreaded programs, theerrno macro in <errno.h> is required by POSIX.1-2001 to expand to a modifiable lvalue of type int with thread-local storage duration, ensuring each thread maintains its own independent copy of the error value without interference from other threads. This design prevents race conditions where one thread's system call or library function could overwrite the error status observed by another thread. Implementations typically achieve this through compiler macros, such as errno = (*__errno_location()) in GNU/Linux systems, where __errno_location() returns a pointer to the thread-specific integer.[3][29]
Prior to widespread adoption of POSIX threads, older threading libraries like LinuxThreads (used in early glibc versions before NPTL in 2003) sometimes exhibited issues with shared errno access in certain configurations, leading to unpredictable error reporting and potential data races in concurrent code.[30] Legacy code assuming a single global errno across the process could thus fail in multithreaded environments, as concurrent modifications would corrupt error values. To mitigate such problems, developers should avoid treating errno as a process-wide global and instead rely on its thread-local nature; for custom per-thread error storage beyond standard errno, POSIX recommends using pthread_key_create() and pthread_getspecific() to manage thread-specific data safely.
The C11 standard and POSIX.1-2008 further reinforce thread safety by mandating that errno has thread storage duration, guaranteeing no data races during access or modification within the same thread, as long as the program adheres to the standards' concurrency rules. This ensures deterministic behavior in concurrent executions without requiring additional synchronization primitives for errno itself. In parallel programming frameworks like OpenMP, which build on POSIX threads, errno propagation is handled via thread-local instances, allowing library calls within parallel regions to set and retrieve errors independently per thread without cross-thread contamination.