linux函数封装需立即捕获errno:检测系统调用失败后下一行保存errno到局部变量,再处理日志或资源,避免后续调用覆盖;strerror/perror应在安全位置使用保存的errno值。

Linux中函数封装时捕获内部执行错误码,核心在于**及时检查系统调用返回值 + 立即读取 errno + 封装层不覆盖原始错误信息**。封装函数本身不产生 errno,它只是透传或转换底层系统调用(如 open、read、write)或库函数失败时留下的 errno 值。
必须在失败后立刻检查 errno
errno 是一个线程局部的全局变量,它的值只在系统调用或标准库函数失败(通常返回 -1、NULL 或特定错误指示值)后被设置。但后续任何可能失败的函数调用(包括 printf、malloc、甚至某些 strlen)都可能无意中修改 errno。
- ❌ 错误写法:先打印日志再查 errno
- ✅ 正确做法:检测到返回值异常后,下一行就取 errno,再做其他操作
封装函数中推荐的错误处理结构
以封装一个安全的文件打开函数为例:
- 检查 open() 返回值;若为 -1,立即保存 errno 到局部变量(如 saved_errno = errno)
- 接着可调用 log_error()、释放临时资源等,不再依赖 errno
- 最终返回自定义错误码(如 -EACCES)或统一错误类型(如 enum myerr),也可直接返回 saved_errno
- 避免在封装函数里调用 strerror 或 perror —— 这些应在最上层(如 main)或日志模块中使用,保证语义清晰
避免 errno 被意外覆盖的常见陷阱
以下操作看似无害,实则可能改写 errno:
- 调用 printf、fprintf、snprintf(尤其格式化失败时)
- 调用 malloc、calloc(内存不足时可能设 errno=ENOMEM)
- 调用 strlen、memcpy 等纯计算函数一般安全,但不可假设所有库函数都如此
- 多线程环境下,只要不跨线程读取 errno,就无需额外保护(因它是 TLS 变量)
配合 strerror 或 perror 输出可读错误信息
当需要向用户或日志输出具体原因时,在错误发生后的“安全位置”调用:
-
strerror(saved_errno):返回静态字符串,适合单线程场景,例如
printf("open failed: %s\n", strerror(saved_errno)); -
perror("open"):自动拼接前缀和 strerror 结果,输出形如
open: Permission denied - 注意:二者都依赖当前 errno 值,所以仍建议传入已保存的错误码,或确保调用前没其他函数干扰











