1. errno:错误代码变量
errno 是一个全局变量(实际上是线程局部存储变量),定义在头文件 <errno.h> 中,用于存储上一次函数调用发生的错误代码。C标准库中很多函数在发生错误时会设置 errno,以便程序可以进一步检查错误的详细信息。
特点:
- 初始值:
errno的初始值是 0。如果一个函数调用成功,它通常不会修改errno。 - 错误代码:
errno的值对应不同的错误类型,例如:EINVAL:无效参数ENOENT:没有找到文件或目录EACCES:权限被拒绝
- 需要注意的是,只有在函数调用明确出错时,
errno的值才有意义。
2. strerror:将错误代码转换为描述性字符串
strerror 函数用于将错误代码(例如 errno 的值)转换为人类可读的字符串描述。
参数:
errnum:错误代码(通常为errno的值)。
返回值:
- 返回一个指向静态字符串的指针,该字符串描述了错误代码。
特别注意:
strerror 返回的字符串由库管理,用户不需要释放,但其内容可能会在后续调用中被覆盖。
3. perror:打印错误信息
perror 函数直接将错误信息打印到标准错误流(stderr)。它结合 errno 的值打印一条描述性消息,通常用于快速调试。
参数:
s:一个用户定义的字符串,通常是发生错误的函数名称或上下文描述。如果传入NULL,仅输出错误描述。
三者的对比与应用场景
| 函数 | 功能 | 参数及返回值 | 应用场景 |
|---|---|---|---|
| errno | 储存错误代码 | 全局变量,存储错误类型代码 | 检查函数是否出错以及出错类型。 |
| strerror | 将错误代码转换为描述性字符串 | 输入错误代码,返回描述性字符串 | 在需要更详细或可读的错误信息时使用。 |
| perror | 打印错误信息到标准错误流 | 输入用户字符串,输出格式化错误消息 | 快速调试和直接打印错误消息。 |
综合示例
以下是一个结合使用 errno、strerror 和 perror 的综合示例:
#include <stdio.h>
#include <errno.h>
#include <string.h>int main() {FILE *file = fopen("nonexistent.txt", "r");if (file == NULL) {// 使用 errno 输出错误代码printf("Error code: %d\n", errno);// 使用 strerror 转换错误信息printf("Error description: %s\n", strerror(errno));// 使用 perror 打印详细错误信息perror("File open failed");}return 0;
}
C语言中 errno、strerror 和 perror 的注意事项
1. errno 的注意事项
-
只在错误发生后读取
errno的值:- 仅当标准库函数调用失败时,
errno的值才有意义。 - 调用成功的函数通常不会修改
errno,因此在成功调用后,不应依赖errno的值。
- 仅当标准库函数调用失败时,
-
errno是线程局部存储:- 在多线程程序中,每个线程有自己的
errno,这保证了线程安全。
- 在多线程程序中,每个线程有自己的
-
初始化
errno为 0:- 在调用某些函数前,如果需要明确判断是否出错,应该将
errno设置为 0。
- 在调用某些函数前,如果需要明确判断是否出错,应该将
-
不要对
errno硬编码判断:- 应该使用标准头文件
<errno.h>中定义的宏(如EACCES,EINVAL),而不是直接比较错误代码值。
- 应该使用标准头文件
-
errno可能被覆盖:- 某些库函数可能会修改
errno的值,因此在多个函数调用中间,如果需要保留errno的值,应该在第一时间保存。
- 某些库函数可能会修改
2. strerror 的注意事项
-
返回值是静态字符串:
strerror返回的字符串是静态分配的,不能被用户修改或释放。- 多次调用可能会覆盖之前返回的字符串。
-
线程安全问题(C99 之前):
- 在某些旧的 C 标准中,
strerror是非线程安全的,因为它返回的是静态字符串。 - 如果需要线程安全的版本,可以使用 POSIX 提供的
strerror_r(取决于实现)。
- 在某些旧的 C 标准中,
-
错误代码的合法性:
- 传递给
strerror的错误代码(errnum)必须是合法的。如果是未定义的错误代码,返回值可能是未指定的字符串。
- 传递给
-
语言支持问题:
strerror返回的错误描述可能根据系统语言环境而变化,程序运行时需要考虑本地化问题。
3. perror 的注意事项
-
直接输出到标准错误流:
perror的输出目标是标准错误流(stderr),不能直接捕获到标准输出流(stdout)。- 如果需要捕获或重定向错误信息,可以改用
strerror格式化后输出。
-
打印时附加前缀字符串:
perror的参数(s)是用户定义的上下文描述字符串。为了清晰的错误日志,应传入适当的上下文信息。- 如果传入
NULL,只输出错误信息。
-
用于调试而非用户交互:
perror打印的错误信息对开发者非常有帮助,但它的格式不适合作为用户提示。- 在用户交互中,建议用
strerror构造更友好的错误消息。
-
与多线程的关系:
perror会输出当前线程的errno对应的错误信息,适合在多线程环境下调试。
-
不可直接修改
errno:perror依赖于errno的值,因此在调用perror之前,不要显式修改errno。
