C 标准库之 <errno.h> 详解与深度解析

关键词: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 高级实践

  1. 多线程安全使用
    不要使用全局变量 errno 共享状态,每个线程都有独立的 errno。
  2. 日志记录和调试
    结合 strerror(errno) 输出到日志中,可快速定位错误原因。
  3. 函数调用前设为 0
    避免函数调用前 errno 已有历史值,造成误判。
  4. 跨平台兼容性
    避免直接依赖 errno 的数值,使用宏名称判断错误类型。

六、总结

  • <errno.h> 提供标准化错误处理机制,使 C 程序能够准确报告运行时错误。
  • errno 是全局整数变量,保存最近一次错误码。
  • 常用宏(如 ENOENT、EIO、EDOM 等)表示不同错误类型。
  • 结合 strerror 或 perror 输出,可快速调试和记录错误。
  • 正确使用 errno 能显著提升程序鲁棒性和可维护性。
相关推荐
dialect_3 小时前
KMP算法
开发语言·c++·算法
总要学点什么3 小时前
第89篇:三维特效-螺旋圆效果——让螺旋臂卷起一圈圈外扩的涟漪
开发语言·javascript·ecmascript·webgl·cesium·空间分析·1024程序员节
开开心心_Every5 小时前
快速隐藏程序工具自定义快捷键一键切换
java·开发语言·前端·spring·智能手机·word·intellij-idea
chenbingjie_c5 小时前
C++ 多态完全指南:从虚函数重写到虚函数表原理
开发语言·c++
吴卫斌5 小时前
定投ETF实战指南(四):行业/主题ETF——定投的“进攻端“
开发语言·python·股票·量化
·present·5 小时前
CSAPP(Bomb lab)
c语言·c++
超级架构师6 小时前
PRAXO-CORE 2.5.0:用 conformance 和显式边界构建 Go Agent 框架
开发语言·人工智能·后端·golang·ai编程·智能体框架·praxo-core
叼烟扛炮7 小时前
Linux 学习笔记(四十三):网络编程进阶——自定义协议解决 TCP 粘包与守护进程
linux·开发语言·网络·笔记·tcp/ip
LMT流氓兔8 小时前
第五单元——第十六课:给书店助手加上网页界面
java·开发语言·jvm·人工智能·oracle·langchain·1024程序员节
专注仿真8 小时前
梯度提升类(XFBoost)算法详解与代码实例
开发语言·人工智能·python·算法·大模型训练·控制算法