Linux 編程中的錯誤處理機制詳解 —— `errno` 全解析

文章目錄

  • 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;符…