♀ 一句话理解 strerror
「将冷冰冰的错误代码(如 2)翻译成人类能看懂的错误信息(如‘文件不存在’)!」
函数原型
#include // 必须包含头文件
char *strerror(int errnum);
入口参数
参数 | 类型 | 比喻解释 |
errnum | int | 错误代码(通常来自 errno 变量) |
返回参数
返回值 | 含义 |
字符串指针 | 错误代码对应的可读描述(如 "No such file or directory") |
- | 始终返回有效指针,但内容可能随系统不同而变化 |
核心功能图解
errno = 2; // 假设发生了错误代码为2的情况
char *msg = strerror(errno);
printf("%s", msg); // 输出:"No such file or directory"
代码实例:文件操作失败时打印错误
场景
尝试打开一个不存在的文件,捕获错误并输出人类可读的信息。
#include
#include // 包含 strerror
#include // 包含 errno
int main() {
FILE *file = fopen("non_existent_file.txt", "r");
if (file == NULL) {
int error_code = errno; // 获取错误代码
char *error_msg = strerror(error_code); // 翻译成文字
printf(" 文件打开失败!原因:%s\n", error_msg);
} else {
fclose(file);
}
return 0;
}
输出结果
文件打开失败!原因:No such file or directory
技术细节剖析
1.错误代码来源:errno
- errno 是一个全局变量,记录最近一次系统调用的错误代码。
- 需要包含
头文件。 - 每次错误发生时,errno 会被覆盖,应立即保存:
int saved_errno = errno; // 先保存再使用
2.返回的字符串是静态内存
- strerror 返回的字符串指针指向静态内存,不可修改:
char *msg = strerror(2); // msg[0] = 'X'; // 错误!会导致未定义行为
3.线程安全问题
- 传统 strerror 在多线程中不安全(所有线程共享静态内存)。
- C11 引入了线程安全版本 strerror_s:
char buf[100]; strerror_s(buf, sizeof(buf), errno); // 安全写入缓冲区
注意事项
- 错误代码的有效性:
- 如果传入无效的错误码(如负数),可能返回未知字符串。
- 合法错误码范围通常为 0 到 <sys/nerr>(系统定义的最大错误码数)。
- 国际化问题:
- 默认返回英文错误信息,若需本地化语言,请使用 perror 或本地化库。
创新用法:自定义错误处理
// 将错误代码和自定义信息结合
void log_error(const char *action) {
int err = errno;
fprintf(stderr, " 操作 [%s] 失败!原因:%s (代码:%d)\n",
action, strerror(err), err);
}
// 使用示例
FILE *file = fopen("data.bin", "rb");
if (file == NULL) {
log_error("打开文件");
exit(1);
}
对比 perror
strerror 的兄弟函数 perror 可以直接打印错误信息,但灵活性较低:
FILE *file = fopen("test.txt", "r");
if (file == NULL) {
perror(" 致命错误"); // 自动附加错误信息
}
// 输出: 致命错误: No such file or directory
选择建议:
- 需要自定义格式 → 用 strerror
- 需要快速打印 → 用 perror
总结
- 核心功能:将数字错误码翻译成可读字符串。
- 适用场景:文件操作、网络通信、系统调用等可能失败的操作。
- 类比记忆:就像手机里的“错误代码查询手册”,输入数字,输出具体问题描述。