关键词:C语言、错误类型、错误码、errno
适用读者:系统编程人员、嵌入式开发工程师、Linux 后端开发人员、内核/驱动爱好者


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


<errno.h> 简介

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

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

注意:errno 并不是函数返回值,它是库函数通过全局变量记录的错误码。


二、errno 变量详解

extern int errno;
  • 类型:int
  • 作用:保存最近一次系统调用或库函数出错的错误码
  • 特点:
    • 线程安全:在多线程程序中,每个线程的 errno 是独立的(通过 TLS 实现)。
    • 初始值:成功调用函数通常不会修改 errno,调用前可设为 0。
    • 跨平台注意:不同操作系统可能定义额外错误码,不要依赖特定数值。

errno 触发机制示意图

系统调用/库函数执行
|
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 文件操作

#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;
      }

输出示例:

Error opening file: No such file or directory (errno=2)

4.2 数学函数错误

#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 系统调用错误

#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 能显著提升程序鲁棒性和可维护性。