C Macro Errno
## C Library Macro - `errno`
The C library macro `errno` is a thread-local, modifiable lvalue set by system calls and some library functions in the event of an error to indicate what went wrong.
`errno` is defined in the `` header file. It acts as an integer variable that stores error codes. When a standard library function encounters an error, it sets `errno` to an appropriate error code. Your program can then inspect this value to diagnose and handle the error gracefully.
---
## Declaration
Below is the declaration for the `errno` macro:
```c
extern int errno;
```
> **Note:** In modern C standards (C89 and later), `errno` is not required to be a simple `extern int` variable. It is typically defined as a macro that expands to a modifiable lvalue of type `int`. This allows it to be implemented using thread-local storage (TLS) to ensure thread safety.
---
## Parameters & Return Value
* **Parameters:** None (it is a macro representing a variable/lvalue).
* **Return Value:** It evaluates to an `int` representing the last error code.
---
## Workflow for Using `errno`
To reliably use `errno` in your application, follow these steps:
1. **Include the Header**: Include `` in your source file.
2. **Reset `errno` (Optional but Recommended)**: Set `errno = 0` before calling a function that might fail.
3. **Call the Function**: Execute the library function or system call.
4. **Check the Return Value**: Verify if the function returned an error indicator (e.g., `NULL`, `-1`, or `EOF`).
5. **Inspect `errno`**: If an error occurred, check the value of `errno` to determine the specific error type.
6. **Handle the Error**: Take appropriate action based on the error code.
---
## Common `errno` Values
The `` header defines symbolic constants for various error codes. Below are some of the most common standard error codes:
| Constant | Description |
| :--- | :--- |
| `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 |
| `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 ioctl for device) |
| `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: Basic Usage of `errno`
The following example demonstrates how to check `errno` when attempting to open a non-existent file.
```c
#include
#include
#include
// Note: Declaring 'extern int errno' manually is optional but historically common.
// Including is the standard and preferred way.
extern int errno;
int main()
{
FILE *fp;
// Attempt to open a file that does not exist
fp = fopen("file.txt", "r");
if (fp == NULL)
{
// Print the numeric value of errno
fprintf(stderr, "Value of errno: %d\n", errno);
// Print the human-readable error message using strerror()
fprintf(stderr, "Error opening file: %s\n", strerror(errno));
}
else
{
fclose(fp);
}
return 0;
}
```
#### Output
If the file `file.txt` does not exist, compiling and running the program will produce the following output:
```text
Value of errno: 2
Error opening file: No such file or directory
```
---
### Example 2: Detailed Error Handling with `switch`
This example demonstrates how to handle specific error codes differently using a `switch` statement.
```c
#include
#include
#include
int main() {
// Attempt to open a file in read-only mode
FILE *file = fopen("nonexistent_file.txt", "r");
if (file == NULL) {
// Inspect the specific error code stored in errno
switch (errno) {
case EACCES:
printf("Error: Permission denied\n");
break;
case ENOENT:
printf("Error: No such file or directory\n");
break;
default:
printf("Error opening file: %s\n", strerror(errno));
break;
}
return 1;
}
// File operations go here...
fclose(file);
return 0;
}
```
---
## Important Considerations
### 1. Thread Safety
In modern, multi-threaded environments, `errno` is thread-safe. It is typically implemented using **Thread-Local Storage (TLS)**. This ensures that each thread has its own independent copy of `errno`, preventing race conditions where one thread overwrites the error code of another.
### 2. Initial and Success Values
* **No Auto-Reset**: Standard library functions **never** reset `errno` to `0` upon successful execution.
* **Stale Values**: If a function fails and sets `errno`, and then a subsequent function succeeds, `errno` will still contain the error code from the first failed function.
* **Best Practice**: Always check the function's return value first to confirm an error occurred before inspecting `errno`. Alternatively, manually set `errno = 0` immediately before making the function call.
### 3. Cross-Platform Differences
While many `errno` constants (like `EINVAL`, `ENOMEM`, `EACCES`) are standardized by POSIX and C standards, different operating systems (e.g., Linux, macOS, Windows) and C standard library implementations may define additional platform-specific error codes. Avoid relying on the exact numeric values of these constants, as they can vary across platforms. Always use the symbolic macros (e.g., `ENOENT`) instead of raw numbers (e.g., `2`).
---
## Best Practices for Error Handling
1. **Always Check Return Values First**: Do not inspect `errno` unless the function's return value explicitly indicates a failure (e.g., returns `NULL`, `-1`, or `EOF`).
2. **Clear `errno` Before Calls**: If you are calling a function that does not have a distinct error return value, set `errno = 0` before the call, and check if `errno != 0` immediately after.
3. **Use Helper Functions**:
* **`strerror(int errnum)`**: Returns a pointer to the textual description string associated with the error code.
* **`perror(const char *s)`**: Prints the string `s` followed by a colon, a space, and the textual description of the current `errno` value to `stderr`.
YouTip