【C/C++】errno/strerror 和 GetLastError()/FormatMessage 的區別

strerrorerrno 詳解

printf("Error: %s\n", strerror(errno));

這行代碼用于在 C 語言中輸出系統錯誤信息,但它與 Windows 的 GetLastError() 有重要區別。下面我將詳細解釋每個部分及其工作原理。

1. 組件解析

errno

  • 定義errno 是一個全局整型變量(在 C11 標準中改為線程局部存儲),定義在 <errno.h> 頭文件中
  • 作用:存儲標準 C 庫函數執行失敗時的錯誤代碼
  • 特點
    • 由標準 C 庫函數設置(如文件操作、內存分配等)
    • 不是 Windows API 錯誤(Windows API 使用 GetLastError()
    • 在多線程環境中,現代編譯器通常將其實現為線程安全的

strerror

  • 原型char *strerror(int errnum);
  • 作用:將錯誤代碼轉換為可讀的錯誤描述字符串
  • 參數:接收一個錯誤碼(通常是 errno 的值)
  • 返回值:指向靜態分配的字符串的指針,描述錯誤信息

2. 典型使用場景

#include <stdio.h>
#include <errno.h>
#include <string.h>int main() {FILE *fp = fopen("nonexistent.txt", "r");if (fp == NULL) {printf("Error: %s\n", strerror(errno));// 或使用 perror 更簡單的方式:perror("Failed to open file");}return 0;
}

3. 與 Windows API GetLastError() 的區別

特性errno/strerrorGetLastError()/FormatMessage
來源標準 C 庫函數設置Windows API 函數設置
頭文件<errno.h>, <string.h><windows.h>
錯誤碼范圍標準 C 定義的錯誤碼Windows 系統錯誤碼
線程安全現代實現中是線程安全的本身就是線程特定的
典型錯誤示例ENOENT(2): 文件不存在ERROR_FILE_NOT_FOUND(2): 系統找不到文件
獲取字符串的函數strerror()FormatMessage()

4. 常見問題

問題1:為什么我的 Windows API 錯誤用 strerror 顯示不正確?

  • 原因:Windows API 錯誤應該使用 GetLastError() + FormatMessage()
  • 示例
    // 錯誤方式(不適用于Windows API錯誤)
    CloseHandle(invalid_handle);
    printf("%s\n", strerror(errno)); // 不會顯示正確的Windows錯誤// 正確方式
    CloseHandle(invalid_handle);
    printf("Error: %d\n", GetLastError()); // 使用FormatMessage更好
    

問題2:errno 的值何時會被覆蓋?

  • 規則
    1. 成功的庫函數調用不會修改 errno(標準規定)
    2. 某些實現可能在成功調用時將 errno 設為 0
    3. 應該立即在函數調用失敗后檢查 errno

問題3:strerror 的返回值有效期是多久?

  • 答案
    • 返回指向靜態字符串的指針,不需要釋放
    • 但后續調用可能會覆蓋該內容(非線程安全實現中)
    • 在 C11 中可以使用 strerror_s 更安全的版本

5. 替代方案

(1) perror() - 更簡單的打印方式

fopen("nonexistent.txt", "r");
if (errno) {perror("File open failed"); // 輸出: "File open failed: No such file or directory"
}

(2) strerror_r (線程安全版本, POSIX)

char buf[256];
strerror_r(errno, buf, sizeof(buf));
printf("Error: %s\n", buf);

(3) C11 的 strerror_s

char buf[256];
strerror_s(buf, sizeof(buf), errno);
printf("Error: %s\n", buf);

6. 典型 errno 錯誤碼示例

錯誤碼描述
EPERM1操作不允許
ENOENT2文件或目錄不存在
EIO5輸入/輸出錯誤
EBADF9錯誤的文件描述符
EAGAIN11資源暫時不可用,請重試
EACCESS13權限不足
EFAULT14錯誤的地址
EBUSY16設備或資源忙
EEXIST17文件已存在
EINVAL22無效參數
ENOSPC28設備無剩余空間

7. 最佳實踐建議

  1. 在 Windows 編程中

    • 對于 Win32 API 錯誤,始終使用 GetLastError() + FormatMessage()
    • 對于標準 C 庫函數,可以使用 errno + strerror()
  2. 跨平臺編程

    #ifdef _WIN32
    // Windows 錯誤處理
    #else
    // POSIX 錯誤處理
    #endif
    
  3. 錯誤處理模板

    #include <stdio.h>
    #include <errno.h>
    #include <string.h>void print_error(const char *context) {#ifdef _WIN32DWORD error = GetLastError();LPSTR buffer = NULL;FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL, error, 0, (LPSTR)&buffer, 0, NULL);fprintf(stderr, "%s: %s (code %d)\n", context, buffer, error);LocalFree(buffer);#elsefprintf(stderr, "%s: %s (code %d)\n", context, strerror(errno), errno);#endif
    }
    

理解這些區別對于正確診斷和報告系統錯誤至關重要,特別是在混合使用標準庫函數和平臺特定API時。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/904488.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/904488.shtml
英文地址,請注明出處:http://en.pswp.cn/news/904488.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Unicode和UTF - 8主要有以下區別

Unicode和UTF - 8主要有以下區別 概念范疇 Unicode:是字符集 。它為世界上幾乎所有的字符(包括各國文字、標點符號、特殊符號等)分配了唯一的編號,這個編號也叫碼位、碼點,比如“中”字的Unicode碼點是U+4E2D 。它規定了字符的抽象表示,只關注字符與數字編號的對應關系,…

企業數字化轉型第二課:接受不完美(1/2)

一.引言 先看一組中國企業數字化轉型相關的數據&#xff1a; 戰略認知層面&#xff1a;92%中國企業將數字化納入戰略核心&#xff08;麥肯錫2023&#xff09;執行困境層面&#xff1a;63%企業轉型首年遭遇重大挫折&#xff08;BCG 2024追蹤&#xff09;價值釋放周期&#xff1…

OSCP - Proving Grounds - Sumo

主要知識點 ShellShock漏洞dirtycow提權 具體步驟 執行nmap掃描,比較直觀&#xff0c;22和80端口開放&#xff0c;但是80端口沒有什么內容 Nmap scan report for 192.168.210.87 Host is up (0.44s latency). Not shown: 65533 closed tcp ports (reset) PORT STATE SERV…

pyqt寫一個TCP(UDP)檢測工具

先用電腦連接到目標WIFI&#xff0c;再運行以下代碼。 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtNetwork import *class NetTestTool(QWidget):def __init__(self):super().__init__()self.init_ui()self.tcp_socket QTcpSocket()…

趣味編程:夢幻萬花筒

目錄 1.效果展示 2.源碼展示 3.代碼邏輯詳解 3.1 頭文件與宏定義 3.2 HSV函數轉RGB顏色函數 3.3 主函數 初始化部分 循環部分 線條繪制部分 刷新和延時部分 結束部分 4.小結 本篇博客主要介紹趣味編程用C語言實現萬花筒小程序。 1.效果展示 2.源碼展示 #define…

軟件開發各階段的自動化測試技術詳解

引言 在當今快速迭代的軟件開發環境中&#xff0c;自動化測試已成為保證軟件質量、提高測試效率的重要手段。本文將深入探討軟件開發生命周期各個階段的自動化測試技術&#xff0c;包括單元測試、代碼級集成測試、Web Service測試和GUI測試的自動化實現方法。 單元測試的自動…

Elasticsearch:我們如何在全球范圍內實現支付基礎設施的現代化?

作者&#xff1a;來自 Elastic Kelly Manrique SWIFT 和 Elastic 如何應對基礎設施復雜性、誤報問題以及日益增長的合規要求。 金融服務公司在全球范圍內管理實時支付方面面臨前所未有的挑戰。SWIFT&#xff08;Society for Worldwide Interbank Financial Telecommunication -…

day009-用戶管理專題

文章目錄 1. 創建包含時間的文件2. 與用戶相關的文件3. 用戶分類4. 與用戶相關的命令4.1 添加用戶4.2 刪除用戶4.3 查看用戶4.4 修改用戶密碼 5. sudo6. 思維導圖7. 老男孩思想-學習方法 1. 創建包含時間的文件 或$()是替換符號&#xff0c;可以將命令的結果作為字符串或變量的…

shell腳本實現遠程重啟多個服務器

直接deepseek幫寫腳本 remoteReboot.sh #!/bin/bash # 配置文件路徑&#xff08;格式&#xff1a;每行一個服務器地址&#xff09; SERVER_FILE"servers.list" # 讀取服務器列表 mapfile -t SERVERS < "$SERVER_FILE" for server in "${SERVER…

如何利用 QuickAPI 生成 PostgreSQL 樣本測試數據:全面解析與實用指南

目錄 一、什么是 QuickAPI&#xff1f; 二、為什么需要生成樣本測試數據&#xff1f; 三、如何在 QuickAPI 中生成 PostgreSQL 樣本測試數據&#xff1f; 1. 登錄 QuickAPI 平臺 2. 選擇 PostgreSQL 數據庫和目標表 3. 配置樣本數據生成規則 4. 導出或直接插入數據 四、…

黑馬點評day04(分布式鎖-setnx)

4、分布式鎖 4.1 、基本原理和實現方式對比 分布式鎖&#xff1a;滿足分布式系統或集群模式下多進程可見并且互斥的鎖。 分布式鎖的核心思想就是讓大家都使用同一把鎖&#xff0c;只要大家使用的是同一把鎖&#xff0c;那么我們就能鎖住線程&#xff0c;不讓線程并行&#x…

?人工智能在農作物病蟲害識別中的應用前景分析

近年來&#xff0c;全球氣候變化加劇、農業種植規模化發展&#xff0c;農作物病蟲害對糧食安全的威脅日益凸顯。據統計&#xff0c;全球每年因病蟲害造成的農作物損失約占總產量的20%-40%&#xff0c;而傳統依賴人工經驗的防治方式效率低、成本高&#xff0c;難以滿足現代農業需…

C++ 完美轉發

C 完美轉發逐步詳解 1. 問題背景與核心目標 在 C 模板編程中&#xff0c;若直接將參數傳遞給其他函數&#xff0c;參數的 值類別&#xff08;左值/右值&#xff09;和 類型信息&#xff08;如 const&#xff09;可能會丟失。例如&#xff1a; template<typename T> voi…

Midjourney 繪畫 + AI 配音:組合玩法打造爆款短視頻!

一、引言:AI 重構短視頻創作范式 在某短視頻工作室的深夜剪輯室里,資深編導正在為一條古風劇情視頻發愁:預算有限無法實拍敦煌場景,人工繪制分鏡耗時 3 天,配音演員檔期排到一周后。而使用 Midjourney 生成敦煌壁畫風格的場景圖僅需 15 分鐘,AI 配音工具實時生成多角色臺…

AI基礎知識(02):機器學習的任務類型、學習方式、工作流程

03 機器學習(Machine Learning)的任務類型與學習方式 廣義的機器學習主要是一個研究如何讓計算機通過數據學習規律,并利用這些規律進行預測和決策的過程。這里的Machine并非物理意義上的機器,可以理解為計算機軟硬件組織;Learning可以理解為一個系統或平臺經歷了某些過程…

數據結構、刷leetcode返航版--二分5/7

1.排序 快排&#xff1a; 第一章 基礎算法&#xff08;一&#xff09; - AcWing 如何調整范圍 經典二分 遞歸結束條件&#xff1b;條件滿足時&#xff0c;進行處理&#xff1b;遞歸左邊&#xff0c;遞歸右邊 分界點劃分可以是l,r,(lr)/2,但是如果是選l&#xff0c;比如是1…

LeetCode 267:回文排列 II —— Swift 解法全解析

文章目錄 摘要描述題解答案題解代碼分析統計字符頻率判斷是否可能構成回文構建半邊字符數組回溯生成半邊排列 示例測試及結果時間復雜度空間復雜度實際使用場景&#xff1a;回文排列在真實項目里能干啥&#xff1f;文本處理、數據清洗類系統游戲開發&#xff1a;名字合法性驗證…

JumpServer批量添加資產

環境說明&#xff1a;我的環境是H3C網絡設備環境 一、在linux系統環境下通過Python腳本獲取交換機信息&#xff0c;IP地址和設備名稱一一對應&#xff0c;腳本如下&#xff1a; cat get_device-sysname.py import re from netmiko import ConnectHandler from concurrent.fut…

理解字、半字與字節 | 從 CPU 架構到編程實踐的數據類型解析

注&#xff1a;本文為 “字、半字、字節” 相關文章合輯。 略作重排&#xff0c;未全校。 如有內容異常&#xff0c;請看原文。 理解計算機體系結構中的字、半字與字節 在計算機科學中&#xff0c;理解“字 (Word)”、“半字 (Half-Word)”和“字節 (Byte)”等基本數據單元的…

數據庫實驗10 函數存儲

數據庫實驗10 一、實驗目的 掌握函數和存儲過程的定義方法&#xff0c;包括標量函數、表值函數、存儲過程的語法結構。理解函數和存儲過程的作用及原理&#xff0c;區分標量函數與表值函數的應用場景&#xff0c;掌握存儲過程的參數傳遞、邏輯控制和錯誤處理機制。能夠熟練運…