errno全局變量
很多系統函數在錯誤返回時將錯誤原因記錄在libc定義的全局變量errno中,每種錯誤原因對應一個錯誤碼,請查閱errno(3)的Man Page了解各種錯誤碼,errno在頭文件errno.h中聲明,是一個整型變量,所有錯誤碼都是正整數。
如:當使用fopen打開文件失敗時,該函數返回NULL,而且同時將錯誤原因記錄在全局變量errno中。
如果在程序中打印錯誤信息時直接打印errno變量,打印出來的只是一個整數值,仍然看不出是什麼錯誤。比較好的辦法是用perror或strerror函數將errno解釋成字符串再打印。
perror函數
#include <stdio.h>
void perror(const char *s);
perror函數將錯誤信息打印到標准錯誤輸出,首先打印參數s所指的字符串,然後打印:號,然後根據當前errno的值打印錯誤原因。例如:
例perror
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp = fopen("abcde", "r");
if (fp == NULL) {
perror("Open file abcde");
exit(1);
}
return 0;
}
如果文件abcde不存在,fopen返回-1並設置errno為ENOENT,緊接著perror函數讀取errno的值,將ENOENT解釋成字符串No such file or directory並打印,最後打印的結果是Open file abcde: No such file or directory。雖然perror可以打印出錯誤原因,傳給perror的字符串參數仍然應該提供一些額外的信息,以便在看到錯誤信息時能夠很快定位是程序中哪裡出了錯,如果在程序中有很多個fopen調用,每個fopen打開不同的文件,那麼在每個fopen的錯誤處理中打印文件名就很有幫助。
如果把上面的程序改成這樣:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void)
{
FILE *fp = fopen("abcde", "r");
if (fp == NULL) {
perror("Open file abcde");
printf("errno: %d\n", errno);
exit(1);
}
return 0;
}
則printf打印的錯誤號並不是fopen產生的錯誤號,而是perror產生的錯誤號。errno是一個全局變量,很多系統函數都會改變它,fopen函數Man Page中的ERRORS部分描述了它可能產生的錯誤碼,perror函數的Man Page中沒有ERRORS部分,說明它本身不產生錯誤碼,但它調用的其它函數也有可能改變errno變量。大多數系統函數都有一個Side Effect,就是有可能改變errno變量(當然也有少數例外,比如strcpy),所以一個系統函數錯誤返回後應該馬上檢查errno,在檢查errno之前不能再調用其它系統函數。
strerror函數
strerror函數可以根據錯誤號返回錯誤原因字符串。
#include <string.h>
char *strerror(int errnum);
返回值:錯誤碼errnum所對應的字符串
這個函數返回指向靜態內存的指針。以後學線程庫時我們會看到,有些函數的錯誤碼並不保存在errno中,而是通過返回值返回,就不能調用perror打印錯誤原因了,這時strerror就派上了用場:
fputs(strerror(n), stderr);
作者 kevinzhangyang