位置:首页 > C > C 语言 :看懂 errno、常见错误码与错误处理方法

C 语言 :看懂 errno、常见错误码与错误处理方法

时间:2026-08-23  |  作者:极客少年  |  阅读:0

目录

  1. 什么是 errno,它解决了什么问题
  2. 开发中常见的 errno 错误码
  3. 什么时候用 strerror
  4. 什么时候用 perror
  5. 如何按错误码做自定义处理
  6. 总结
展示 C 程序中从函数调用失败到读取 errno、输出错误信息的基本处理流程图
errno 的基本使用流程把返回值判断、读取 errno、选择输出方式串成一条清晰流程。

前言

在 C 程序里,函数失败并不等于问题已经说清楚了,很多真正有用的线索都藏在 errno 里。本文从 的基本作用讲起,再到常见错误码、strerrorperror 的使用差异,以及如何按错误码做分支处理,帮助你判断一次失败究竟是参数问题、权限问题,还是资源和环境问题。

在 C 程序里,很多系统调用和标准库函数失败时,不会直接告诉你完整原因,而是把线索留在 errno 里。这也是为什么不少初学者明明判断到了失败,却还是很难继续定位问题。

这篇文章就围绕 展开:先说明 errno 到底记录了什么、什么时候该看它,再把常见错误码按场景归类,最后结合 strerrorperror 和自定义处理代码,整理出一套更实用的排错方法。

什么是 errno,它解决了什么问题

是 C 标准库中的头文件,其中定义了全局错误标识 errno。它的类型通常是 int,用于保存系统调用或库函数最近一次失败时对应的错误代码。

可以把 errno 理解成“失败原因编号”。当某个操作执行失败后,程序往往先通过返回值告诉你“这次没成功”,再通过 errno 告诉你“为什么失败”。例如文件不存在、权限不足、参数无效、内存不足,都可能对应不同的错误码。

先判断失败,再读取 errno

使用 errno 时有一个关键前提:先看函数是否真的失败。只有当返回值已经表明调用失败时,再去检查 errno 才有意义。

展示 errno 常见错误码按文件、网络、线程、系统资源四类归纳的分类信息图
常见 errno 错误码分类把分散的错误码按使用场景归类,方便读者在排错时快速缩小范围,而不是逐个死记硬背。

为了使用它,需要包含头文件

这段代码里,fopen 试图打开不存在的 nonexistent_file.txt。如果打开失败,返回值是 NULL,此时 errno 很可能会被设置为 ENOENT,表示文件或目录不存在。

错误码的取值由系统决定

errno 的具体错误码并不是完全由 C 语言本身统一规定,而是会受到操作系统实现影响。以 Linux 为例,常见值包括:

  • EACCES:权限不够。
  • EBADF:文件描述符无效。
  • EINVAL:无效参数。
  • ENOENT:文件或目录不存在。
  • ENOMEM:内存不足。

这也意味着,同样是“调用失败”,只有结合具体错误码,才能知道后续该重试、提示用户、修正参数,还是直接退出。

开发中常见的 errno 错误码

单独记忆错误码意义不大,按场景来理解更实用。下面把原文提到的常见错误码分成几类,便于在排查问题时快速定位。

文件操作相关

  • EACCES:没有权限访问文件或目录。
  • EBADF:文件描述符无效。
  • ENOENT:文件或目录不存在。
  • ENOTDIR:路径中的某个部分不是目录。
  • EISDIR:试图对目录进行文件操作。
  • EROFS:只读文件系统。

这一组最常见,通常出现在 fopenopenreadwrite 一类文件操作中。只看“打开失败”并不足够,像“文件不存在”和“权限不足”虽然结果都是失败,但修复方式完全不同。

展示 strerror、perror 与自定义错误处理三种方式区别及适用场景的信息图
三种错误处理方式怎么选把三种错误处理方式的定位放在一起比较,帮助读者判断什么时候直接打印,什么时候拼接日志。

网络相关

  • ECONNREFUSED:连接被拒绝。
  • ETIMEDOUT:连接超时。
  • EHOSTUNREACH:主机不可达。
  • ENETDOWN:网络未就绪。

网络错误更适合结合上下文处理。例如连接被拒绝,可能说明服务端没有监听;超时则更可能是链路不稳定、目标端响应过慢,或者超时参数设置太短。

线程相关

  • EDEADLK:检测到死锁。
  • EINVAL:无效参数。
  • ENOMEM:内存不足。

这类错误一般出现在多线程同步、锁操作或线程创建相关接口中。它们往往不是偶发故障,而是代码逻辑本身存在设计问题,需要回到并发控制流程里排查。

系统资源相关

  • ENOMEM:内存不足。
  • EMFILE:进程打开的文件描述符太多。
  • ENFILE:系统打开的文件描述符太多。

这一类错误通常说明程序已经碰到资源上限。相比单纯打印错误信息,更重要的是确认资源是否及时释放,以及当前负载是否超出系统设计范围。

什么时候用 strerror

strerror 的作用,是把整数形式的错误码转换成可读的错误消息字符串。它适合用在你已经拿到了 errno,并希望把信息拼接进自己的日志、报错输出或提示文案时。

这个例子中,strerror(errno) 会返回与当前错误码对应的文本说明,再由 fprintf 输出到标准错误流。

它的优势是灵活:你可以把错误消息和文件名、参数值、调用阶段等业务上下文拼在一起,形成更完整的诊断信息。

什么时候用 perror

如果你只是想快速把最近一次错误打印出来,perror 会更省事。它会自动读取当前的 errno,转换为对应消息,并输出到标准错误流。

这里的 perror("Error opening file") 会在你给出的前缀后面,附加系统生成的错误说明。它非常适合做调试期输出,或者在命令行工具里快速报告失败原因。

简单理解,两者的区别是:

  • strerror 适合你自己组织输出格式。
  • perror 适合快速直接打印当前错误。

如何按错误码做自定义处理

真正实用的错误处理,通常不止是“打印一下”。很多时候,你需要根据不同错误码决定下一步动作,比如提示用户检查路径、提示权限问题,或者走不同的补救流程。

这个写法的重点,不只是 switch 分支本身,还在于先把当前错误码保存到局部变量 err。这样做可以避免后续其他函数调用影响你要处理的错误上下文。

一套更稳妥的使用思路

  • 先检查函数返回值,确认调用确实失败。
  • 失败后立即读取或保存 errno
  • 根据场景选择 perrorstrerror 或分支处理。
  • 把错误码和调用上下文一起记录,避免只留下模糊的“执行失败”。

这样做的结果是,程序不仅能报错,还能给出足够明确的排查方向。

总结

的价值,不在于单纯多了一个错误编号,而在于它把“失败”进一步细化成了可分析、可分类、可处理的原因。只要掌握“先判断失败,再读取 errno”这个基本原则,并根据场景选用 strerrorperror 或自定义分支,C 程序的错误处理就会清晰很多。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多