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

关键词:C语言、错误类型、错误码、errno

适用读者:系统编程人员、嵌入式开发工程师、Linux 后端开发人员、内核/驱动爱好者


在 C 语言编程中,错误处理 一直是程序员必须面对的重要问题。C 标准库提供了 <errno.h> 头文件,它定义了一系列用于报告和处理运行时错误的机制。本文将系统讲解 <errno.h> 的作用、常用宏、使用方法及注意事项,并配以实例和图示,帮助你在编程中更加高效地处理错误。


<errno.h> 简介

<errno.h> 提供了一种标准化的方式来报告程序运行时错误。

  • 定义全局变量 errno,用于存储最近发生的错误代码。
  • 系统调用或库函数在失败时会设置 errno 来指示错误类型。
  • 定义了大量宏来表示不同错误类型,如 EPERMENOENTEIO

注意: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 是全局整数变量,保存最近一次错误码。
  • 常用宏(如 ENOENTEIOEDOM 等)表示不同错误类型。
  • 结合 strerrorperror 输出,可快速调试和记录错误。
  • 正确使用 errno 能显著提升程序鲁棒性和可维护性。
相关推荐
胡八一3 小时前
30 分钟上手 exp4j:在 Java 中安全、灵活地计算数学表达式
java·开发语言·安全
郝学胜-神的一滴4 小时前
Linux 进程控制块(PCB)解析:深入理解进程管理机制
linux·服务器·开发语言
后端小张4 小时前
【鸿蒙开发手册】重生之我要学习鸿蒙HarmonyOS开发
开发语言·学习·华为·架构·harmonyos·鸿蒙·鸿蒙系统
胖咕噜的稞达鸭4 小时前
AVL树手撕,超详细图文详解
c语言·开发语言·数据结构·c++·算法·visual studio
-SGlow-4 小时前
Linux相关概念和易错知识点(48)(epoll的底层原理、epoll的工作模式、反应堆模式)
linux·服务器·c语言·网络·c++
007php0074 小时前
百度面试题解析:synchronized、volatile、JMM内存模型、JVM运行时区域及堆和方法区(三)
java·开发语言·jvm·缓存·面试·golang·php
芒果量化4 小时前
Optuna - 自动调参利器&python实例
开发语言·python·算法·机器学习
foundbug9995 小时前
基于CSMA-CA协议的V2X通信MATLAB仿真
开发语言·网络·matlab
cellurw5 小时前
Day67 Linux I²C 总线与设备驱动架构、开发流程与调试
linux·c语言·架构