YouTip LogoYouTip

C Standard Library Errno H

# C Standard Library - `` The `` header file in the C Standard Library provides a standardized mechanism for reporting and handling runtime errors. It defines the global/thread-local variable `errno` and a set of integer constants representing specific error codes. When a system call or library function encounters an error, it typically sets `errno` to a specific value indicating what went wrong. --- ## Introduction to `errno` The `errno` macro expands to a modifiable lvalue of type `int`. It can be read and modified by the program. Historically, `errno` was a global `int` variable. However, in modern multi-threaded environments, it is typically implemented as a thread-local variable (using Thread-Local Storage, or TLS). This ensures that error codes in one thread do not overwrite or interfere with those in another thread. ### How it Works 1. **Initial State**: At program startup, `errno` is initialized to `0`. 2. **Function Failure**: When a standard library function or system call fails, it sets `errno` to a non-zero value representing the specific error. 3. **No Reset on Success**: If a library function succeeds, it is **not** required to clear or reset `errno` to `0`. Therefore, you should only check `errno` after a function has returned a value indicating failure (e.g., returning `NULL`, `-1`, or `EOF`). --- ## Core Library Macros According to the ISO C standard, `` must define at least the following three macros: | Macro | Description | | :--- | :--- | | `errno` | A macro that expands to a modifiable lvalue of type `int`, representing the most recent error code. | | `EDOM` | **Domain Error**: Occurs when an input argument to a mathematical function is outside the domain over which the function is defined (e.g., `sqrt(-1)`). | | `ERANGE` | **Range Error**: Occurs when the result of a mathematical function cannot be represented by the return type due to overflow or underflow (e.g., `pow(10, 1000)`). | --- ## Common POSIX Error Codes In addition to the standard C macros (`EDOM`, `ERANGE`), POSIX-compliant systems (like Linux and macOS) define a wide range of error macros in ``. Below are some of the most frequently used error codes: * **`EPERM`**: Operation not permitted * **`ENOENT`**: No such file or directory * **`ESRCH`**: No such process * **`EINTR`**: Interrupted system call * **`EIO`**: Input/output error * **`ENXIO`**: No such device or address * **`E2BIG`**: Argument list too long * **`ENOMEM`**: Out of memory / Cannot allocate memory * **`EACCES`**: Permission denied * **`EFAULT`**: Bad address * **`EBUSY`**: Device or resource busy * **`EEXIST`**: File exists * **`EXDEV`**: Cross-device link * **`ENODEV`**: No such device * **`ENOTDIR`**: Not a directory * **`EISDIR`**: Is a directory * **`EINVAL`**: Invalid argument * **`ENFILE`**: File table overflow * **`EMFILE`**: Too many open files * **`ENOTTY`**: Not a typewriter (inappropriate I/O control operation) * **`ETXTBSY`**: Text file busy * **`EFBIG`**: File too large * **`ENOSPC`**: No space left on device * **`ESPIPE`**: Illegal seek * **`EROFS`**: Read-only file system * **`EMLINK`**: Too many links * **`EPIPE`**: Broken pipe --- ## Code Examples ### Example 1: Handling File I/O Errors This example demonstrates how to check `errno` when `fopen` fails, and how to use `strerror` from `` to print a human-readable error message. ```c #include #include #include int main() { // Attempt to open a file that does not exist FILE *file = fopen("nonexistent_file.txt", "r"); if (file == NULL) { // fopen failed, errno has been set to the appropriate error code (likely ENOENT) printf("Error opening file: %s (Error Code: %d)\n", strerror(errno), errno); return 1; } // File operations go here... fclose(file); return 0; } ``` ### Example 2: Handling Mathematical Domain and Range Errors This example demonstrates how mathematical functions set `errno` to `EDOM` or `ERANGE`. ```c #include #include #include #include int main() { // Reset errno to 0 before the operation errno = 0; // Domain Error: Square root of a negative number double val = sqrt(-1.0); if (errno == EDOM) { printf("Domain Error occurred: %s\n", strerror(errno)); } // Reset errno to 0 before the next operation errno = 0; // Range Error: Exponential overflow double val2 = exp(1000.0); if (errno == ERANGE) { printf("Range Error occurred: %s\n", strerror(errno)); } return 0; } ``` --- ## Best Practices and Considerations ### 1. Thread Safety In modern C (C11 and later) and POSIX environments, `errno` is thread-safe. It is implemented as a thread-local variable, meaning each thread has its own local copy of `errno`. You do not need to worry about race conditions on `errno` when multiple threads are executing system calls simultaneously. ### 2. Always Reset `errno` Before Certain Calls Because successful library calls do not clear `errno`, you should manually set `errno = 0` before calling functions where checking `errno` is the only reliable way to detect an error (such as `strtol` or `strtod`). ```c errno = 0; long val = strtol(str, &endptr, 10); if (errno != 0) { // An overflow or underflow error occurred } ``` ### 3. Check Return Values First Never rely on the value of `errno` unless the function's return value explicitly indicates that an error occurred. If a function succeeds, the value of `errno` is undefined and may contain leftover error codes from previous failed operations. ### 4. Do Not Rely on Specific Integer Values Always use the symbolic macros (like `EINVAL`, `ENOMEM`, `EDOM`) instead of their raw integer values (like `22`, `12`, `33`). The actual integer values assigned to these macros can vary across different operating systems and CPU architectures.
← C Standard Library Float HC Standard Library Ctype H β†’