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

C 標準庫 I/O 錯誤處理:errno、perror 與 strerror 完全指南

     編輯:關於C語言

錯誤報告機制概覽

C 標準庫函數失敗時,通常返回特殊值(如 NULL、-1、EOF),並將錯誤代碼存入全局變量 errno。errno 定義於 <errno.h>,為執行緒局部存儲(現代實現),各錯誤代碼對應具體原因(如 ENOENT、EACCES)。

三大錯誤處理工具

1. 直接檢查 errno

#include <errno.h>
#include <stdio.h>

FILE* fp = fopen("data.txt", "r");
if (fp == NULL) {
    // errno 現為具體錯誤碼,如 ENOENT=2
    fprintf(stderr, "fopen failed, errno=%d\n", errno);
}

缺點:僅得數字,無語義,需查表對照。

2. perror — 直接輸出到 stderr

#include <stdio.h>

FILE* fp = fopen("data.txt", "r");
if (fp == NULL) {
    perror("Open data.txt");  // 輸出:Open data.txt: No such file or directory
}
  • 格式:用戶字串: 系統錯誤信息
  • 自動讀取當前 errno 並轉換為文本。
  • 注意:perror 內部可能調用其他庫函數,導致 errno 被覆寫。若需保留原始 errno,應先保存:int saved_errno = errno; perror(...);。

3. strerror — 獲取錯誤信息字串

#include <string.h>
#include <errno.h>

char* msg = strerror(errno);  // 返回靜態緩衝區指標
fprintf(stderr, "Error: %s\n", msg);
  • 適用於需自定義輸出格式、或錯誤碼非來自 errno(如 pthread 函數返回錯誤碼)的場景。
  • 返回指標指向靜態區,非線程安全(C11 提供 strerror_s / strerror_r)。

最佳實踐模式

FILE* safe_fopen(const char* path, const char* mode) {
    FILE* fp = fopen(path, mode);
    if (fp == NULL) {
        int err = errno;                 // 立即保存
        fprintf(stderr, "ERROR [%s:%d] fopen('%s', '%s'): %s\n",
                __FILE__, __LINE__, path, mode, strerror(err));
        errno = err;                     // 還原(可選)
    }
    return fp;
}

常見陷阱

陷阱後果對策
在檢查 errno 前調用其他庫函數errno 被覆寫,失去原始錯誤緊跟失敗調用後檢查/保存 errno
假設 perror 不修改 errno實際可能修改先保存 errno 再調用 perror
多線程直接用 strerror 返回指標靜態緩衝區競爭用 strerror_r 或複製字串
忽略返回值直接用 errno函數成功時 errno 未定義僅在返回值指示失敗時檢查 errno

標準錯誤碼速查

  • EACCES (13) — 權限被拒
  • EAGAIN (11) — 資源暫不可用(非阻塞 I/O)
  • EBADF (9) — 非法文件描述符
  • EINTR (4) — 系統調用被信號中斷
  • EINVAL (22) — 參數無效
  • EMFILE (24) — 進程打開文件過多
  • ENFILE (23) — 系統打開文件過多
  • ENOENT (2) — 文件/目錄不存在
  • ENOMEM (12) — 記憶體不足
  • ENOSPC (28) — 磁盤空間不足

總結

  1. errno 是錯誤碼容器,perror 適合快速調試輸出,strerror 適合程式化處理。
  2. 「檢查返回值 → 立即保存 errno → 格式化輸出」是工業級錯誤處理鐵律。
  3. 多線程環境優先使用 strerror_r 或 C11 strerror_s。

熟練掌握此三件套,讓你的 C 程式在面對 I/O 失敗時既健壯又可診斷。

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