天天看點

《UNIXLinux程式設計教程》一1.6 錯誤處理

unix的系統調用和大部分庫函數在失敗時會傳回一特殊值報告出錯,這個特殊值通常是–1。這種傳回值僅告訴調用遇到了錯誤而已,為了讓應用知道究竟發生了什麼錯誤,系統調用和庫函數同時還會在系統定義的變量errno中給出指明錯誤原因的錯誤碼。

變量errno是系統調用和庫函數用來報告錯誤的一種标準方法。早期的unix和c将它實作為外部整型變量,其說明為:

這是程序中的全局共享變量,無法支援多線程。為了支援多線程,新的posix标準和c标準在要求這個變量為整型左值的同時,還規定一個線程對errno的讀寫不受其他線程更改errno的影響。是以,新的unix和c實作已經改變為每個線程各自有自己對應的errno。例如,linux将其定義為:

這樣,每個線程便可通過内建的專門函數獲得各自errno的存儲單元。

頭檔案定義了變量errno以及它可以取值的錯誤碼。每一種錯誤碼有一個符号名,它們是定義在中以字母'e'開頭的宏名字。所有錯誤碼的值都是正整數且除了ewouldblock和eagain之外每一個都互不相同。是以,可以用它們作為switch語句内的case标号來區分錯誤情形。表1-1列出了一些常見的錯誤碼。

程式開始時,變量errno的初值一定是0,unix的系統調用和許多庫函數當遇到錯誤時均保證設定該變量為某個非0值。errno的值隻有在函數調用出錯時才被設定,函數調用成功則不會改變,它可能是前一次調用某個函數出錯時的值。是以,不應當用errno來檢測一個調用是否失敗。正确的做法是僅當函數的傳回值指出這個變量被明顯設定時才用errno來确定錯誤原因。

《UNIXLinux程式設計教程》一1.6 錯誤處理

不會有任何函數設定errno的值為0來指出錯誤,errno的這個性質可以用來檢測某些特殊函數的錯誤傳回值。有少數函數,如1.8.3節介紹的pathconf(),在出現錯誤的情況下仍傳回一個合法值,但同時也設定errno。對于這些函數,如果我們想檢測是否遇到了錯誤,應當在調用它們之前置errno為0,函數調用之後再檢查其值。我們在程式1-3中會見到這種情況的例子。

errno的錯誤碼是整數,c标準函數strerror()可将錯誤碼轉換為可讀的報錯資訊。

strerror()傳回與errnum錯誤碼相對應的錯誤資訊字元串。我們不能修改由strerror()傳回的字元串,同樣,如果緊接着再次調用strerror(),前一次調用得到的字元串将被覆寫。

如果想直接将errno目前值對應的錯誤資訊輸出到标準報錯檔案,則可調用perror()。

perror()首先列印msg指定的資訊,後随一個冒号和空格,然後列印與errno對應的錯誤字元串。

如果msg是空指針或指向空字元串,perror()列印的将是與strerror()完全相同的資訊,但perror()附加有換行符,而strerror()沒有。

例1-1 當系統調用或庫函數發生錯誤時,在有些情況下會需要立即終止程式的運作,因為繼續執行已沒有意義。此時,可以用perror()或strerror()這兩個函數之一列印出對應的錯誤資訊,然後調用exit(1)終止程式的執行。本書的很多例子就是這種情況。為此,我們統一使用一個函數err_exit()來完成報告錯誤并退出的動作。這個函數以宏方式定義在我們的頭檔案err_exit.h(程式1-1)中,其中,宏調用參數message給出使用者需要輸出的資訊。

《UNIXLinux程式設計教程》一1.6 錯誤處理

本書在介紹每一個函數時,有時會省略傳回值的說明,此時除非特殊說明,均遵循unix的一般約定:調用成功的傳回值是0,錯誤傳回值是–1,并設定了錯誤碼于errno中。