文章目录

  • Linux 编程中的错误处理机制详解 —— `errno` 全解析
    • 一、什么是 `errno`?
      • ❓为什么需要 `errno`?
      • ✅ 它在哪里定义?
    • 二、errno 的设置与读取规则
      • ⚠️ errno 不是总是有效!
      • ❗使用 errno 的正确步骤:
    • 三、与 errno 配套使用的函数
      • 示例:
    • 四、errno 常见错误码及含义
    • 五、errno 是线程安全的吗?
    • 六、errno 封装建议
    • 七、errno 与系统调用的配合使用
      • open() 示例:
      • read() 示例:
    • 八、如何查看 errno 对应的错误码?
    • 九、调试技巧:gdb 查看 errno
    • 🔟 附录:示例程序 - 模拟打开文件失败
    • ✅ 总结

Linux 编程中的错误处理机制详解 —— errno 全解析

在 Linux C 系统编程中,我们时常会与各种系统调用打交道,如 open()read()write()fork()socket() 等。错误处理是程序鲁棒性的重要组成部分,而 errno 就是标准库为我们提供的重要错误处理机制。本文将全面详细讲解 errno 的原理、用法、注意事项、线程安全特性及实践案例。


一、什么是 errno

errno 是一个全局变量,代表最近一次系统调用或标准库函数失败时的错误码。它是 int 类型,但为了线程安全,现代实现中实际为“线程局部存储”(TLS),即每个线程有自己的 errno 值

❓为什么需要 errno

很多系统调用或库函数在失败时只返回 -1 或 NULL,并不告诉你具体错误信息。此时就需要查询 errno 来获得错误原因。

✅ 它在哪里定义?

你需要引入头文件:

#include <errno.h>

它在 <errno.h> 中的定义通常为:

extern int errno;

但实际实现如下(glibc):

#define errno (*__errno_location())  // 或 __errno()

意味着每个线程调用 errno 实际是访问一个局部的 int 指针,避免线程间干扰。


二、errno 的设置与读取规则

⚠️ errno 不是总是有效!

  • 仅当系统调用 失败时,系统才会设置 errno
  • 成功调用不会清除 errno,所以你不能通过 errno == 0 判断成功与否。

❗使用 errno 的正确步骤:

errno = 0;  // 可选,清除旧错误
int fd = open("nofile.txt", O_RDONLY);
if (fd == -1) {// open 失败,可以读取 errnoprintf("Error code: %d\n", errno);printf("Message: %s\n", strerror(errno));
}

三、与 errno 配套使用的函数

函数作用
perror()打印系统调用错误及自定义前缀
strerror(errno)返回错误码对应的错误字符串
strerror_r()线程安全版本,写入用户缓冲区

示例:

if ((fp = fopen("test.txt", "r")) == NULL) {perror("fopen");fprintf(stderr, "详细错误:%s\n", strerror(errno));
}

四、errno 常见错误码及含义

宏名说明
EPERM1操作不被允许
ENOENT2文件或目录不存在
ESRCH3没有匹配的进程
EINTR4系统调用中断
EIO5I/O 错误
EBADF9无效的文件描述符
EACCES13权限不足
EEXIST17文件已存在
ENOTDIR20不是目录
EISDIR21是目录
EINVAL22参数无效
ENFILE23系统打开的文件数已达上限
EMFILE24进程打开的文件数已达上限
ENOSPC28设备空间不足

可通过 man 3 errno 查看完整列表。


五、errno 是线程安全的吗?

是的,在现代 glibc 实现中是线程安全的。

虽然 errno 看起来像一个全局变量,但实际是通过 __errno_location() 这样的函数返回每个线程自己的 errno 变量,确保在多线程中使用不会冲突。


六、errno 封装建议

为了代码复用和统一日志格式,可以封装错误打印:

void report_errno(const char* msg) {fprintf(stderr, "[ERROR] %s: %s (errno: %d)\n", msg, strerror(errno), errno);
}

使用示例:

if (close(fd) == -1) {report_errno("close failed");
}

七、errno 与系统调用的配合使用

open() 示例:

int fd = open("test.txt", O_RDONLY);
if (fd < 0) {perror("open");
}

read() 示例:

char buffer[128];
int n = read(fd, buffer, sizeof(buffer));
if (n < 0) {fprintf(stderr, "read error: %s\n", strerror(errno));
}

八、如何查看 errno 对应的错误码?

方法一:终端查看 man 手册

man 3 errno
man 3 strerror

方法二:查看头文件定义

cat /usr/include/asm-generic/errno-base.h
cat /usr/include/asm-generic/errno.h

方法三:自定义测试代码输出:

for (int i = 0; i < 50; ++i) {printf("errno %d: %s\n", i, strerror(i));
}

九、调试技巧:gdb 查看 errno

在 GDB 中调试程序出错时,可使用:

(gdb) print errno
(gdb) print strerror(errno)

确保你在出错系统调用之后立即查看,否则 errno 值可能被覆盖。


🔟 附录:示例程序 - 模拟打开文件失败

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>int main(void) {int fd = open("nonexist.txt", O_RDONLY);if (fd == -1) {fprintf(stderr, "打开失败: %s (errno = %d)\n", strerror(errno), errno);return 1;}close(fd);return 0;
}

✅ 总结

关键点说明
errno 的本质一个线程局部变量,记录最近一次失败的错误码
设置时机系统调用或函数失败时设置,成功时不修改
获取错误信息方式strerror(errno) 获取描述,perror() 自动输出
多线程安全性是,现代系统通过线程局部存储实现
使用注意事项只能在调用失败时使用,切勿误判

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/90032.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/90032.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/90032.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣-最长递增子序列

简单记录学习~给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。示例…

公司内部网址怎么在外网打开?如何让外网访问内网的网站呢?

很多公司内部本地会部署有中小型的服务器&#xff0c;可以很好的方便用于一些办公业务系统&#xff0c;或测试开发需要。在数字化办公和生活场景中&#xff0c;除了公司内部局域网内访问公司系统外&#xff0c;经常会遇到需要让外网访问内网网站的情况。比如企业员工远程办公时…

有趣的css - 多选立体标签按钮

&#x1f36d; 大家好&#xff0c;我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;今天分享的是一个交互较完整的多选立体标签按钮。 最新文章通过公众号「设计师工作日常」发布。 目录整体效果核心代码html 代码css 部分代码完整代码如下html 页面css 样式页面渲…

C++中byte*和char*的区别

在C中&#xff0c;byte*&#xff08;通常指 std::byte*&#xff09;和 char* 都是指针类型&#xff0c;但它们在语义和用途上有重要区别&#xff1a;1. 类型定义char* char 是C内置的基本类型&#xff0c;表示字符&#xff08;通常是1字节&#xff09;。 char* 常用于&#xff…

【node】npm包本地开发与调试

npm link 进入本地的 babel-plugin-function-try-catch 这个 npm 包的根目录执行&#xff1a; npm link上面的命令可以将当前的这个包安装在全局&#xff08;mac 中的路径是 /usr/local/bin&#xff09;&#xff0c;也就是 npm i -g 安装包的目录。 执行后结果如图&#xff…

突破量子仿真瓶颈:微算法科技MLGO量子算法的算术化与核操作迭代模型

近年来&#xff0c;量子计算机的迅速发展和潜在的强大计算能力吸引了全球科研机构和企业的广泛关注。量子计算机利用量子力学的特性来处理复杂的计算任务&#xff0c;具有在某些方面远超经典计算机的潜力。然而&#xff0c;真正实用的量子计算机尚未大规模普及&#xff0c;因此…

python中读取 Excel 表格数据

在pandas中读取 Excel 表格后&#xff0c;有多种方式可以按列、按行提取数据&#xff0c;下面我将详细介绍常见的方法。 0.声明 在本文中我使用的excel表内容如下&#xff1a;1. 读取 Excel 文件 首先&#xff0c;我们需要使用 pandas 的 read_excel 函数读取 Excel 文件&#…

算法训练营day28 贪心算法②122.买卖股票的最佳时机II、55. 跳跃游戏、 45.跳跃游戏II 、1005.K次取反后最大化的数组和

贪心算法第二篇博客&#xff01;感觉这篇博客中的算法都很巧妙&#xff0c;需要动动脑筋 122.买卖股票的最佳时机II &#xff08;这道题可以遍历数组&#xff0c;如果不能遍历的话&#xff0c;就不能做了&#xff0c;需要注意的是&#xff1a; 只有一只股票&#xff01;当前只…

NumPy核心操作全攻略

NumPy&#xff08;Numerical Python&#xff09;是 Python 生态中用于科学计算的核心库&#xff0c;提供高性能的多维数组对象&#xff08;ndarray&#xff09;及相关的数学运算工具。其核心功能围绕数组操作、线性代数、随机数生成等&#xff0c;是数据科学、机器学习等领域的…

Redis 主从同步对象模型

淘汰策略 对最外层的key进行淘汰 expire(秒)/pexpire(毫秒) ttlmaxmemory:最大内存的一半(持久化fork()子进程) 数据迁移需要额外的空间 maxmemory-policy 提供淘汰机制 默认不会淘汰 lru 最近最少使用 lfu最近最少频次 voltaile 对由expire的进行淘汰持久化: fork:写时复制原理…

C++ 使用 constexpr 、查表法、分治法加速位镜像翻转

代码////// brief 左右翻转位。////// note 翻转后&#xff0c;最低位位将变为最高位&#xff0c;最高位将变为最低位。//////template <typename T>requires(std::is_same_v<T, uint8_t>)constexpr T Reverse(T value){int32_t bit_count sizeof(T) * 8;for (int…

知识库搭建之Meilisearch‘s 搜索引擎 测评-东方仙盟测评师

windows 启动后 启动成功后关键信息 Config file path: "none" Database path: "./data.ms" Server listening on: "http://localhost:7700" Environment: "development" Commit SHA: &quo…

【笔记】Anaconda 重装后虚拟环境写入路径异常的完整排查与解决过程

Anaconda 安装[仅为当前用户安装/为所有用户安装]选项对环境变量设置的影响_anaconda没有添加环境变量-CSDN博客 Anaconda 路径治理指南&#xff1a;路径精简、权限优化与环境隔离-CSDN博客 Windows系统下手动升级Anaconda的详细指南_anaconda升级-CSDN博客 Conda 命令大全&…

QuecPython-正则表达式

该模块通过正则表达式匹配数据。目前支持的操作符较少&#xff0c;部分操作符暂不支持。示例&#xff1a;import ureres $GNRMC,133648.00,A,3149.2969,N,11706.9027,E,0.055,,311020,,,A,V*18 $GNGGA,133648.00,3149.2969,N,11706.9027,E,1,24,1.03,88.9,M,,M,,*6C $GNGLL,3…

QT窗口(3)-状态栏

QT窗口&#xff08;3&#xff09;-状态栏 状态栏 代码如下&#xff1a;//存在就获取&#xff0c;不存在就创建QStatusBar*statusBarthis->statusBar();this->setStatusBar(statusBar);//显示一个临时消息statusBar->showMessage("这是一个状态消息");运行结…

更具个性的域名:解锁互联网多元价值的钥匙

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

深度学习模块实践手册(第十一期)

46、缩放点积注意力模块论文《Attention Is All You Need》1、作用&#xff1a; 缩放点积注意力&#xff08;Scaled Dot-Product Attention&#xff09;是 Transformer 模型的核心组件&#xff0c;旨在解决序列建模中长距离依赖关系捕捉的问题。传统的循环神经网络&#xff08;…

C++高级技术详解

C高级技术详解 目录 模板 (Templates)右值和移动语义 (Rvalue and Move Semantics)定位 new (Placement new)强类型 (Strong Types)智能指针 (Smart Pointers)容器和算法 (Containers and Algorithms)Lambda表达式常量表达式 (constexpr)多线程和并发 (Multithreading and Co…

跨境卖家紧急自查,Endryko Karmadi四季版画版权维权

25年7月2日&#xff0c;Keith律所代理印尼艺术家Endryko Karmadi发起全新版权维权行动。案件基本情况&#xff1a;起诉时间&#xff1a;2025-7-2案件号&#xff1a;25-cv-07436品牌&#xff1a;Endryko Karmadi Work原告&#xff1a;Endryko Karmadi 原告律所&#xff1a;keith…

M3088NL是一款网络滤波器/变压器支持100M和1000M网络环境,适用于高速网络传输场景M3088

M3088NL是一款网络滤波器/变压器&#xff0c;主要特点如下&#xff1a;兼容性 支持100M和1000M网络环境&#xff0c;适用于高速网络传输场景。 ‌封装形式 采用SOP/SOIC封装&#xff0c;便于电路集成。 ‌应用场景 常用于网络电话、开关电源等需要稳定电流的设备&#xff0c;符…