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 能显著提升程序鲁棒性和可维护性。
相关推荐
无相求码31 分钟前
C程序的内存到底怎么分的?栈、堆、全局区一张图讲清楚
c语言
格林威40 分钟前
工业相机Chunk功能全解析:图像嵌入时间戳、编码器元数据(附堡盟C#代码)
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·工业相机
小大宇1 小时前
Python 集成 Conda
开发语言·python·conda
天空'之城1 小时前
C 语言工业级通用组件手写 08:精准软件消抖
c语言·嵌入式开发·工业级组件·软件消抖·按键防抖
还是奇怪1 小时前
Simon Willison 用 DSPy 优化 Datasette Agent 提示词:提示工程正在变成可测试的软件工程
java·开发语言·软件工程
小大宇2 小时前
python flask框架 SSE流式返回、跨域、报错
开发语言·python·flask
Legendary_0083 小时前
LDR6500 设计指南:Type-C 音频快充二合一配件 PD 取电与插拔时序控制方案
c语言·开发语言·音视频
柒星栈3 小时前
PHP 源码怎么加密防破解?三套方案实战指南
开发语言·php·android studio
勉灬之3 小时前
Next.js + Prisma 跨平台部署踩坑记
开发语言·javascript·ecmascript
这是个栗子3 小时前
前端开发中的常用工具函数(九)
开发语言·javascript·ecmascript·at