编程参考 - 如何判断errno是否可用

errno 是标准 C 语言中的全局变量,定义在 <errno.h> 头文件中,用于存储系统调用和某些库函数在发生错误时设置的错误代码。

errno is a global variable in standard C. It is defined in the <errno.h> header and is used to store error codes set by system calls and some library functions when an error occurs.

不过,虽然 errno 在概念上是全局变量,但在支持线程的环境中,它是线程安全的。在这种情况下,每个线程都有自己的 errno 版本,通常使用线程本地存储实现,这样并发操作就不会相互干扰。

However, while errno is conceptually global, it is thread-safe in environments that support threads. In such cases, each thread has its own version of errno, typically implemented using thread-local storage, so that concurrent operations do not interfere with each other.

在 Linux(和 POSIX 系统)中,函数可以修改全局变量 `errno` 来表示发生了错误。如果想知道函数是否会修改 `errno` ,有几种方法:
In Linux (and POSIX systems), functions can modify the global variable `errno` to indicate that an error has occurred. If you want to know whether a function will modify `errno`, there are several approaches you can take:
1. Check the Function's Documentation / 检查文档
确定一个函数是否修改了 `errno` 的最可靠方法是查阅其官方文档。Linux man 页(手册页)通常会提供这方面的信息。例如
   - 使用 `man` 查看函数的 man 页。
   - 修改 `errno` 的函数通常会在 man 页的 “错误”部分明确提及。
   The most reliable way to determine if a function modifies `errno` is by consulting its official documentation. The Linux man pages (manual pages) usually provide this information. For example:
   - Use `man` to check the function's man page.
   - Functions that modify `errno` typically mention it explicitly in the "Errors" section of the man page.
Example:
man 2 open
在 `open(2)` man 页面中,您可以找到 “错误 ”部分,其中列出了函数将设置 `errno` 的各种条件,以及可能设置的 `errno` 值(错误代码)(例如 `EACCES`、`EEXIST` 等)。
In the `open(2)` man page, you'll find an "Errors" section that lists various conditions under which the function will set `errno` and what `errno` values (error codes) may be set (e.g., `EACCES`, `EEXIST`, etc.).
2. POSIX and Standard Library Behavior / POSIX标准和标准库行为
   根据 POSIX 标准:
   - 失败的函数通常会将 `errno` 设置为非零值,以指示错误情况。
   - 如果函数成功,则不应更改 `errno`。
   - 即使没有错误发生,函数也允许设置 `errno` ,因此 `errno` 只有在函数指示失败(例如返回 `-1`)时才有效。
   因此,如果函数可能失败,它可以修改 `errno`。没有失败条件的函数(如 `strlen`)不会修改 `errno`。
   According to the POSIX standard:
   - Functions that fail typically set `errno` to a non-zero value to indicate the error condition.
   - If a function succeeds, it should not change `errno`.
   - Functions are allowed to set `errno` even if no error occurs, so `errno` is only valid when the function indicates a failure (e.g., returning `-1`).
   Therefore, if a function can fail, it may modify `errno`. Functions that have no failure conditions (e.g., `strlen`) will not modify `errno`.
3. Common System Functions that Modify `errno` / 会修改errno的通用系统函数
一些通常会修改 `errno` 的函数包括:
   - 文件操作(`open`、`read`、`write`、`close`、`stat` 等)。
   - 内存管理函数(`malloc`、`free`、`mmap` 等)。
   - 进程控制函数(`fork`、`exec`、`wait` 等)。
   - 网络和套接字函数(`socket`、`connect`、`send` 等)。
Some functions commonly known to modify `errno` include:
   - File operations (`open`, `read`, `write`, `close`, `stat`, etc.).
   - Memory management functions (`malloc`, `free`, `mmap`, etc.).
   - Process control functions (`fork`, `exec`, `wait`, etc.).
   - Network and socket functions (`socket`, `connect`, `send`, etc.).
当发生错误时,执行 I/O、内存分配或系统调用的函数通常会修改 `errno` 。
Functions that perform I/O, memory allocation, or system calls typically modify `errno` when an error occurs.
4. Checking the Source Code / 检查源代码
如果您使用的是开源软件,例如 GNU C 库 (glibc),您可以检查源代码,查看函数是否设置了 `errno`。在许多情况下,系统调用或封装系统调用的函数会在失败时设置 `errno`。
If you're working with open-source software, such as the GNU C Library (glibc), you can check the source code to see if the function sets `errno`. In many cases, system calls or functions that wrap system calls will set `errno` when they fail.
Example:
errno = 0;
int fd = open("file.txt", O_RDONLY);
if (fd == -1) {
    // Check errno for the specific error
    perror("open failed");
}
5. Test the Function / 使用测试函数
如果不确定,可以测试函数是否会改变 `errno`。在调用函数前将 `errno` 设为 0,然后在函数返回后检查 `errno`。这并不适用于所有情况,但却是一种有用的实验技术。
If you're unsure, you can test whether a function changes `errno`. Set `errno` to 0 before calling the function, and then check `errno` after the function returns. This won't work for all cases, but it's a useful technique for experimentation.
Example:
#include <stdio.h>
#include <errno.h>
int main() {
    errno = 0;    // Clear errno
    printf("Before call: errno = %d\n", errno);
    int result = open("non_existent_file.txt", O_RDONLY);
    if (result == -1) {
        printf("After call: errno = %d\n", errno);
        perror("open");
    }
}
在本例中,“open ”函数设置了 “errno”,因为文件不存在。
In this example, the `open` function sets `errno` because the file does not exist.
6. Standards and Guarantees / 标准和惯例
   - POSIX 函数: 执行系统级操作的 POSIX 兼容函数通常会在失败时设置 `errno`。
   - C 标准库函数: 许多标准 C 库函数(如 `strtol`、`fopen` 等)会在发生错误时设置 `errno`。
   - POSIX Functions: POSIX-compliant functions that perform system-level operations generally set `errno` on failure.
   - C Standard Library Functions: Many standard C library functions (like `strtol`, `fopen`, etc.) set `errno` when an error occurs.
Summary
- 查看文档: 请务必查阅手册或官方文档,以确定函数是否设置了 `errno`。
- POSIX 标准: 可能失败的函数通常会设置 `errno`,但 `errno` 只有在函数发出错误信号(例如返回 `-1`)时才有意义。
- 源代码: 对于开源库,您可以查看代码,了解 `errno` 是如何处理的。
- 测试函数: 您可以通过手动设置和检查函数调用周围的 `errno` 来进行实验,看看它是否会发生变化。
- Check the documentation: Always consult the man pages or the official documentation to see if a function sets `errno`.
- POSIX standard: Functions that can fail typically set `errno`, but `errno` is only meaningful if the function signals an error (e.g., by returning `-1`).
- Source code: For open-source libraries, you can look at the code to see how `errno` is handled.
- Test the function: You can experiment by manually setting and checking `errno` around function calls to see if it changes.
在大多数情况下,关于函数是否会在失败时修改 `errno` 的问题,man 页会提供最明确的答案。
In most cases, the man page will provide the clearest answer as to whether a function will modify `errno` upon failure.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜流冰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值