关键词:C语言、错误类型、错误码、errno
适用读者:系统编程人员、嵌入式开发工程师、Linux 后端开发人员、内核/驱动爱好者
在 C 语言编程中,错误处理 一直是程序员必须面对的重要问题。C 标准库提供了 <errno.h>
头文件,它定义了一系列用于报告和处理运行时错误的机制。本文将系统讲解 <errno.h>
的作用、常用宏、使用方法及注意事项,并配以实例和图示,帮助你在编程中更加高效地处理错误。
<errno.h>
简介
<errno.h>
提供了一种标准化的方式来报告程序运行时错误。
- 定义全局变量
errno
,用于存储最近发生的错误代码。 - 系统调用或库函数在失败时会设置
errno
来指示错误类型。 - 定义了大量宏来表示不同错误类型,如
EPERM
、ENOENT
、EIO
等
注意:
errno
并不是函数返回值,它是库函数通过全局变量记录的错误码。
二、errno
变量详解
c
extern int errno;
- 类型:
int
- 作用:保存最近一次系统调用或库函数出错的错误码
- 特点:
- 线程安全 :在多线程程序中,每个线程的
errno
是独立的(通过 TLS 实现)。 - 初始值 :成功调用函数通常不会修改
errno
,调用前可设为 0。 - 跨平台注意:不同操作系统可能定义额外错误码,不要依赖特定数值。
- 线程安全 :在多线程程序中,每个线程的
errno
触发机制示意图
yaml
系统调用/库函数执行
|
v
函数返回值检查
|
成功? ------→ 不修改 errno
|
v
失败
|
设置 errno
|
v
用户获取 errno
|
strerro/perror 输出
三、常见错误码及含义
下面是 <errno.h>
中常用的错误码:
错误码 | 描述 |
---|---|
EPERM | 操作不允许 |
ENOENT | 没有这样的文件或目录 |
ESRCH | 没有这样的进程 |
EINTR | 系统调用被中断 |
EIO | 输入/输出错误 |
ENXIO | 没有这样的设备或地址 |
E2BIG | 参数列表太长 |
ENOMEM | 内存不足 |
EACCES | 权限被拒绝 |
EFAULT | 坏的地址 |
EBUSY | 资源忙 |
EEXIST | 文件已存在 |
EXDEV | 跨设备链接 |
ENODEV | 没有这样的设备 |
ENOTDIR | 不是一个目录 |
EISDIR | 是一个目录 |
EINVAL | 无效的参数 |
ENFILE | 系统文件表溢出 |
EMFILE | 打开的文件过多 |
ENOTTY | 不是终端设备 |
ETXTBSY | 文本文件忙 |
EFBIG | 文件过大 |
ENOSPC | 设备上没有空间 |
ESPIPE | 非法寻址 |
EROFS | 只读文件系统 |
EMLINK | 链接过多 |
EPIPE | 管道破裂 |
Tip:C 程序中可根据不同
errno
进行针对性处理,提高程序鲁棒性。
四、使用 errno 的示例
4.1 文件操作
c
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main() {
FILE *file = fopen("nonexistent_file.txt", "r");
if (!file) {
printf("Error opening file: %s (errno=%d)\n", strerror(errno), errno);
return 1;
}
fclose(file);
return 0;
}
输出示例:
yaml
Error opening file: No such file or directory (errno=2)
4.2 数学函数错误
c
#include <stdio.h>
#include <math.h>
#include <errno.h>
int main() {
errno = 0; // 调用前清零
double val = sqrt(-1.0); // 不合法的平方根
if (errno == EDOM) {
printf("Math error: domain error\n");
}
return 0;
}
4.3 系统调用错误
c
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
int main() {
int fd = open("/root/secret_file.txt", O_RDONLY);
if (fd == -1) {
perror("Failed to open file"); // perror 自动打印 errno 对应的错误信息
}
return 0;
}
五、errno
高级实践
- 多线程安全使用
不要使用全局变量errno
共享状态,每个线程都有独立的errno
。 - 日志记录和调试
结合strerror(errno)
输出到日志中,可快速定位错误原因。 - 函数调用前设为 0
避免函数调用前errno
已有历史值,造成误判。 - 跨平台兼容性
避免直接依赖errno
的数值,使用宏名称判断错误类型。
六、总结
<errno.h>
提供标准化错误处理机制,使 C 程序能够准确报告运行时错误。errno
是全局整数变量,保存最近一次错误码。- 常用宏(如
ENOENT
、EIO
、EDOM
等)表示不同错误类型。 - 结合
strerror
或perror
输出,可快速调试和记录错误。 - 正确使用
errno
能显著提升程序鲁棒性和可维护性。