[筆記] System Call的錯誤處理

System Call的錯誤處理

檢查錯誤是非常好的習慣,因為你在未來的某一天,很可能會因為沒有養成這個習慣,花費數十個小時在抓一個「這應該不大可能出錯」的System Call上。因此在使用System Call時,請養成檢查錯誤的習慣。
每次系統呼叫失敗的時候,通常會回傳一個特殊的值,絕大多數的情況下是-1,或是NULL,極少數情形是其他特殊的值。這些回傳值只是告訴你:你已經死了,至於你是怎麼死的,他們會留下驗屍的線索,也就是errno。
一開始程式啟動時,errno是0,代表一切正常。但隨著程式出現錯誤,errno會被設成非0的值,代表錯誤的代碼。透過檢查這個代碼,可以得知是哪種類型的死因,就可以有個驗屍的方向。
標準的驗屍流程是這樣的:

  1. 檢查回傳值,看看自己是不是死掉了
  2. 如果死掉了,檢查errno驗屍

關於errno,有以下幾條規則

  • 成功的System Call或Library function不會將errno設成0
  • 但成功的System Call可以將errno設成其他非0值(這是SUSv3允許的,儘管很少人會這麼做)
  • 連續兩次的System Call,後面的System Call可能會覆蓋掉前面的errno

用來印出錯誤訊息的System Call有兩個,分別是perror和strerror

perror

perror會印出自訂的msg字串,然後加一個分號和空白 : ,然後直接印出該errno所代表的錯誤訊息到stderr上。
通常自訂的msg字串會是剛剛使用的系統呼叫,這樣比較好除錯。
範例:

strerror()

strerror()會接收錯誤代碼,並回傳錯誤訊息的字串指標,這可以讓我們方便印出更格式化的錯誤訊息。

範例:

有一點要注意的是,因為實作上回傳的字串所使用的空間可能永遠是同一個,因此連續兩次sterror的呼教可能會把第一次呼叫的字串洗掉。

特殊情況

  • getpriority()的成功回傳值可能是-1,因此要檢查錯誤時,你必須先把errno設成0,呼叫完之後進行檢查看看是否有出錯。
  • 極少數的System Call永遠不會出錯,可以不用檢查。像是getpid(), _exit()

我要如何得知errno數字所代表的錯誤名稱?

這是研究這段時產生的疑問,我能不能透過errno反查錯誤名稱(例如EOVERFLOW),而不只是印出錯誤字串。答案是,可以但是非常麻煩,你不會想要這麼做。請參閱這則stackoverflow上的問題How can I print the symbolic name of an error in c
如果你真的想知道錯誤訊息是哪個錯誤名稱,可以直接man errno去對照比較快。

資料來源

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *