首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

glibc 錯誤報告機制深度解析:errno、strerror、perror 與 error() 完整指南

     編輯:關於C語言

核心概念:錯誤碼與 errno

glibc 函式通常回傳特殊值(-1、NULL、EOF)表示失敗,但無法得知具體錯誤原因。真正的錯誤資訊儲存在全域變數 errno(定義於 <errno.h>,型別 volatile int)。

正確使用 errno 的鐵律

  1. 不要用 errno 判斷是否出錯:成功時不會清零,殘留舊值會誤導。
  2. 先檢查函式回傳值確認失敗,再讀取 errno 取得錯誤碼。
  3. 呼叫前可選擇性歸零errno = 0,便於事後比對。
  4. 查閱函式文件確認該函式支援哪些錯誤碼。

常見錯誤碼宏(定義於 errno.h 及相關頭文件)

宏名含義典型場景
EDOM定義域錯誤數學函式參數超出定義域(如 sqrt(-1))
ERANGE值域錯誤結果超出可表示範圍(如 exp(1000))
EAGAIN/EWOULDBLOCK資源暫時不可用非阻塞 IO 無資料、鎖被佔用
EFAULT無效指標傳遞野指標給系統呼叫(幾乎所有系統通用)
EAGAIN 與 EWOULDBLOCK 數值相同,switch 判斷需謹慎,唯一可信來源是文件。

錯誤訊息報告函式

1. strerror() / strerror_r() —— 取得錯誤描述字串

#include <string.h>
char *strerror(int errnum);           // 非執行緒安全,回傳靜態緩衝區
char *strerror_r(int errnum, char *buf, size_t n); // 執行緒安全,寫入使用者緩衝區
  • strerror:MT-Unsafe race:strerror,多執行緒環境下資料競爭。
  • strerror_r:MT-Safe,但回傳值與 buf 皆可能指向靜態區,需注意 GNU 版本差異(XSI vs GNU)。

2. perror() —— 直接列印至 stderr

#include <stdio.h>
void perror(const char *message);
  • message == NULL:僅列印錯誤描述(如 "No such file or directory")。
  • message != NULL:列印 "message: 錯誤描述" 格式。
  • 必須緊接失敗呼叫使用,避免 errno 被後續函式覆蓋。

3. 程式名稱變數

char *program_invocation_name;        // 等同 argv[0] 完整路徑
char *program_invocation_short_name;  // 僅程式名稱(無目錄)

需定義 _GNU_SOURCE 並連結 glibc,非 GNU 系統無效。

4. error() / error_at_line() —— GNU 專用格式化錯誤報告(推薦)

void error(int status, int errnum, const char *format, ...);
void error_at_line(int status, int errnum, const char *fname, unsigned int lineno, const char *format, ...);
  • status == 0:格式化列印錯誤,error_message_count++,繼續執行。
  • status != 0:列印後呼叫 exit(status) 終止程式。
  • 輸出格式:程式名: 格式化字串: errno描述(error_at_line 額外含檔名:行號)。
  • 全域變數 error_print_progname 可自訂程式名輸出邏輯;error_one_per_line 非零時每行僅列印一錯誤。

BSD 風格函式(<err.h>,GNU 系統不推薦)

warn(), vwarn(), warnx(), vwarnx()
err(), verr(), errx(), verrx()

功能類似 error() 族但介面不同,移植性考量下優先使用 GNU 版本。

實戰最佳實踐範本

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <error.h>

void read_config(const char *path) {
    FILE *fp = fopen(path, "r");
    if (!fp) {
        error(EXIT_FAILURE, errno, "無法開啟設定檔 '%s'", path);
    }
    // ...
}

總結

glibc 提供層次豐富的錯誤報告機制:errno 為核心,strerror_r 供執行緒安全取字串,perror 供快速列印,error()/error_at_line() 為格式化報告首選。遵循「先查回傳值、再讀 errno、最後查文件」流程,配合 _GNU_SOURCE 使用 error() 族函式,能構建健壯、可維護的錯誤處理體系。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved