程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> glibc_error reporting,glibc_error

glibc_error reporting,glibc_error

編輯:關於C語言

glibc_error reporting,glibc_error


  很多GNU C庫裡的函數都會偵測並報告錯誤條件。我們的程序需要檢測這些錯誤條件。比如:我們打開一個輸入文件時需要判斷該文件是否正確的打開。如果沒有正確打開,我們需要打印錯誤或者采取其他正確的方式。為了利用這種錯誤報告機制,我們需要包含頭文件errno.h

檢測錯誤:

  很多庫函數都會返回一個特殊的值來顯示函數運行出錯。常見的特殊值有:-1、空指針、EOF常量。但是這些返回值只能告訴你有錯誤產生,但不會告訴你錯誤是什麼。如果你想知道錯誤是什麼,就得靠錯誤代碼,錯誤代碼存儲在變量errno中(在errno.h中有聲明)

  errno變量包含了系統錯誤代碼,其類型是volatile。該類型意味著其可以突然被異步線程改變,編譯器從不假設其值。如果你在寫信號處理程序應當保存改變量的值並恢復其值。

  errno的初始值為0,遇到錯誤時,errno絕無可能為0。但沒有錯誤的時候,errno也不一定為0(庫函數在成功運行時並不會修改errno的值)。所以,不要依據errno的值來判斷錯誤是否發生。正確的做法是為每一個函數做好文檔,標注出錯誤代碼的值對應的錯誤類型。這樣調用失敗時,你可以通過檢查errno獲取錯誤代碼,然後查詢函數文檔獲取錯誤詳情。如果你想獲取某一庫函數的錯誤代碼,最好再次之前設置errno為0(或許你還想先保存以下errno的值,然後便於恢復該值)。

  每一個錯誤代碼都有一個以E開頭緊跟大寫字母或數字的符號名,實際為定義在errno.h中的宏。當然不是所有的宏都定義在一個errno.h中(詳細的可以自己翻一翻頭文件,注意不僅僅只有一個errno.h,多個errno.h共同定義了全部的宏)

  錯誤代碼的值一般為正數並且都不相同,但也有一個例外:EWORLDBLOCK和EAGAIN的錯誤代碼是一樣的。除了EWORLDBLOCK和EAGAIN,你可以使用switch語句來判斷錯誤代碼。但你不應該依賴於此,你唯一可以相信的就是文檔。

  除了GNU/Hurd系統,幾乎所有的系統調用被傳入一個無效指針時都會返回EFAULT。所以呢,glibc的函數庫說明文檔中往往會省略對EFAULT的解釋。

  大多數的錯誤代碼宏名都顯而易見的好懂,如果實在不知其意可以查看手冊或者

~# man errno

這裡簡單提幾個宏:

Macro: int EDOM
    域錯誤,可以理解為定義域錯誤。主要用在數學函數中。如果數學函數的一個參數值不在函數定義域中,則會將errno設置為EDOM

Macro: int ERANGE
    范圍錯誤,與上面的EDOM恰好相反。EDOM是定義域的話,ERANGER就是值域了。也多用於數學函數中。如果數學函數返回值超過了約定的返回,則會將errno設置為ERANGE

Macro: int EAGAIN
    資源暫時不可獲得。這種錯誤可能是隨機的,你再次運行的時候便好了。。。EWOULDBLOCK是EAGAIN的一個別名。

 

錯誤消息:

  我們知道錯誤代碼,但總覺得查文檔不方便。幸好庫文件給我們提供了錯誤消息報告函數。這些函數可以報告一個具有說明性的錯誤消息。部分消息報告函數我們可以自己定義消息格式。

  函數strerror和perror為每一個錯誤代碼都提供了一個標准的錯誤消息。而變量program_invocation_short_name則可以方便獲取程序的名字,告訴我們哪個程序出錯。

幾個函數原型:

#include <string.h>
char * strerror(int errnum);
char *strerror_r(int errnum, char *buf, size_t n);

說明:  strerror和strerror_r兩個函數差不多。區別在於安全性,官方文檔對strerror的注釋是MT-Unsafe race:strerror,而strerror_r則為MT-Safe。strerror返回一個靜態申請的字符串緩沖區,該緩沖區被所有線程共享。而strerror_r返回的是一個私有副本,並不被其他線程共享。另外這兩個函數都有可能造成內存溢出(靜態申請的緩沖區)。盡管strerror_r可以指定字符串長度,但這長度是char *buf的。這函數有兩個返回值,一個使用reurn返回,還有一個是char *buf。return返回的依舊是一個靜態緩沖區。

 

#include<stdio.h>
void perror(const char *message);

說明:  perror將error message打印到標准錯誤輸出中。如果你傳進的參數是一個空指針,perror會根據errno打印錯誤消息。如果char *message非空,perror會將message當作錯誤消息的前綴輸出。perror得立即調用,不然errno的值可能發生變化。

 

char *program_invocation_name; //等同於argv[0]
char *program_invocation_short_name //不包含目錄名。

說明:  這兩個變量的初始化工作由glibc庫在還未調用main函數之前執行。所以在非GNU庫中,這兩個變量不起效果,在實際代碼中我們需要定義_GNU_SOURCE宏,告訴編譯器使用GNU庫。

  以下兩個函數在整個GNU project中使用非常廣泛。

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有關,如果status是0,則正常格式化打印錯誤消息。全局變量error_message_count也會做自增操作。錯誤消息的格式如下:program_name: format_string: error_messager_for_errno\n。如果status非零,這兩個函數將調用exit status,即以狀態status退出(不會返回)。關於program_name:全局變量error_print_progname指向的函數決定了program_name的值。error_at_line函數有點特別:多了fname,lineno兩個參數。錯誤消息格式如下:program_name:fname:lineno format_string: error_mesage_for_errno\n。如果全局變量error_one_per_line被設置為非零值,每一行只會打印一個錯誤消息。

  除了以上的錯誤消息函數,我們還有以下幾個:這幾個函數主要用在BSD系統中,定義在頭文件err.h中,在gnu系統中不推薦使用。

void warn(const char *format, ...)
void vwarn(const char *format, va_list ap)
void warnx(const char *format, ...)
void vwarnx(const char *format, va_list ap)
void err(int status, const char *format, ...)
void verr(int status, const char *format, va_list ap)
void errx(int status, const char *format, ...)
void verrx(int status, const char *format, va_list ap)

各位看官自行查看手冊吧。just be a man!!!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved