Unix錯(cuò)誤信息傳遞--errno

這篇博客介紹了unix錯(cuò)誤處理中重要的概念:errno,介紹了它的定義十电,作用和注意事項(xiàng)

一. 錯(cuò)誤總是不可避免的...

在計(jì)算機(jī)中因?yàn)楦鞣N內(nèi)外部原因,錯(cuò)誤是不可避免的疚沐,異常處理是程序的組成部分。
比如潮模,我們想獲取一個(gè)文件的基本信息亮蛔,可以調(diào)用系統(tǒng)函數(shù)

int stat(const char *restrict pathname, struct stat *restrict buf);

如果成功,文件的信息會(huì)通過(guò)第二個(gè)參數(shù)buf返回再登;但也可能會(huì)失敗尔邓,失敗的原因可能是
文件不存在晾剖,也可能是沒(méi)有訪問(wèn)權(quán)限或者其他原因锉矢。
那么操作系統(tǒng)如何告訴我們發(fā)生了錯(cuò)誤?更進(jìn)一步齿尽,操作系統(tǒng)如何告知調(diào)用者錯(cuò)誤的具體
原因呢沽损?

根據(jù)stat函數(shù)的man文檔,我們知道循头,可以通過(guò)返回值來(lái)判斷是否成功绵估,返回值等于0表
示成功,返回-1表示失敗
那具體錯(cuò)誤原因呢卡骂?這時(shí)errno就登場(chǎng)了国裳,errno相當(dāng)于一個(gè)錯(cuò)誤碼,當(dāng)stat發(fā)生
錯(cuò)誤時(shí)全跨,會(huì)設(shè)置errno的值缝左,我們可以通過(guò)檢查errno來(lái)得到具體的錯(cuò)誤信息。

一般的代碼片段如下:

    struct stat sb;
    if (stat("./not_exist.txt", &sb) == -1)
    {
        printf("errorno is: %d\n", errno);
        printf("error msg produced by strerror(): %s\n", strerror(errno));
        perror("error msg produced by perror");
    }

上述代碼中浓若,strerrorperror是兩個(gè)有用的函數(shù)渺杉。strerror能夠?qū)?code>errno轉(zhuǎn)化為
對(duì)應(yīng)錯(cuò)誤信息的字符串,perror能夠直接打印出錯(cuò)誤信息挪钓,errno沒(méi)有出現(xiàn)在perror
的輸入?yún)?shù)中是越,這個(gè)問(wèn)題后面在講

二 常見(jiàn)錯(cuò)誤碼

Linux中可以通過(guò)man errno.3指令來(lái)查看常見(jiàn)錯(cuò)誤碼,錯(cuò)誤碼作為常量定義在errno.h
文件中碌上,常見(jiàn)的錯(cuò)誤碼定義如下(取自errno-bash.h文件):

#define EPERM        1  /* Operation not permitted */
#define ENOENT       2  /* No such file or directory */
#define ESRCH        3  /* No such process */
#define EINTR        4  /* Interrupted system call */
#define EIO      5  /* I/O error */
#define ENXIO        6  /* No such device or address */
#define E2BIG        7  /* Argument list too long */
#define ENOEXEC      8  /* Exec format error */
#define EBADF        9  /* Bad file number */
#define ECHILD      10  /* No child processes */
#define EAGAIN      11  /* Try again */
#define ENOMEM      12  /* Out of memory */
#define EACCES      13  /* Permission denied */
#define EFAULT      14  /* Bad address */
#define ENOTBLK     15  /* Block device required */
#define EBUSY       16  /* Device or resource busy */
#define EEXIST      17  /* File exists */
#define EXDEV       18  /* Cross-device link */
#define ENODEV      19  /* No such device */
#define ENOTDIR     20  /* Not a directory */
#define EISDIR      21  /* Is a directory */
#define EINVAL      22  /* Invalid argument */
#define ENFILE      23  /* File table overflow */
#define EMFILE      24  /* Too many open files */
#define ENOTTY      25  /* Not a typewriter */
#define ETXTBSY     26  /* Text file busy */
#define EFBIG       27  /* File too large */
#define ENOSPC      28  /* No space left on device */
#define ESPIPE      29  /* Illegal seek */
#define EROFS       30  /* Read-only file system */
#define EMLINK      31  /* Too many links */
#define EPIPE       32  /* Broken pipe */
#define EDOM        33  /* Math argument out of domain of func */
#define ERANGE      34  /* Math result not representable */

錯(cuò)誤碼可以分為兩類:致命錯(cuò)誤和非致命錯(cuò)誤倚评。
致命錯(cuò)誤無(wú)法恢復(fù),程序只能立刻終止運(yùn)行
非致命錯(cuò)誤大多數(shù)情況下暫時(shí)的(比如網(wǎng)絡(luò)短暫異常)馏予,程序可以處理這些錯(cuò)誤天梧,稍后重試,
增強(qiáng)程序健壯性

三 注意事項(xiàng)

errno有兩個(gè)性質(zhì):

  1. 正常的系統(tǒng)調(diào)用不會(huì)改變errno的值吗蚌,只有錯(cuò)誤的系統(tǒng)調(diào)用才會(huì)修改errno的值
    這意味著腿倚,errno始終記錄著最近一次調(diào)用錯(cuò)誤的錯(cuò)誤碼,我們不能通過(guò)檢查errno來(lái)
    判斷是否發(fā)生錯(cuò)誤,是否發(fā)生錯(cuò)誤需要通過(guò)系統(tǒng)調(diào)用的返回值來(lái)判斷敷燎,在確定發(fā)生了錯(cuò)誤
    之后暂筝,在去檢查errno獲得具體的錯(cuò)誤原因。
    這個(gè)性質(zhì)也是一開(kāi)始提到的perror不需要errno作為參數(shù)的原因硬贯。
  2. errno不會(huì)等于0

四 errno的內(nèi)部實(shí)現(xiàn)

errno是一個(gè)整數(shù)焕襟,可以簡(jiǎn)單實(shí)現(xiàn)為:

extern int errno

上面的實(shí)現(xiàn)方式非常簡(jiǎn)單,可惜在多線程的情況下會(huì)發(fā)生錯(cuò)誤饭豹,因?yàn)楫?dāng)多個(gè)線程需要同時(shí)修改
errno時(shí)鸵赖,前一個(gè)線程的值會(huì)被后一個(gè)線程覆蓋,因此拄衰,每一個(gè)現(xiàn)成需要自己的errno
Linux中它褪,errno的真實(shí)定義是:

extern int *_ _errno_location(void);
#define errno (*_ _errno_location())

例子

#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <string.h>  //strerror()

/**
 * When an error occurs in one of the UNIX System functions, a negative value 
 * is often returned, and the integer errno is usually set to a value that 
 * tells why
 */
int
main(int argc, char* argv[])
{
    struct stat sb;
    if (stat("./not_exist.txt", &sb) == -1)
    {
        printf("errorno is: %d\n", errno);
        printf("error msg produced by strerror(): %s\n", strerror(errno));
        perror("error msg produced by perror");
    }
    if (stat("./errno.c", &sb) == 0)
    {
        //errno is never cleared by a routine if an error does not occur
        perror("last error msg is");
    } 
}

輸出結(jié)果為:

errorno is: 2
error msg produced by strerror(): No such file or directory
error msg produced by perror: No such file or directory
last error msg is: No such file or directory

參考資料

  • Linux系統(tǒng)文件:/usr/include/asm-generic/errno-base.h
  • Advanced Programming in the Unix Environment(3rd) P14 Error Handling
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市翘悉,隨后出現(xiàn)的幾起案子茫打,更是在濱河造成了極大的恐慌,老刑警劉巖妖混,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件老赤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡制市,警方通過(guò)查閱死者的電腦和手機(jī)抬旺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)祥楣,“玉大人开财,你說(shuō)我怎么就攤上這事∪傺撸” “怎么了床未?”我有些...
    開(kāi)封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)振坚。 經(jīng)常有香客問(wèn)我薇搁,道長(zhǎng),這世上最難降的妖魔是什么渡八? 我笑而不...
    開(kāi)封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任啃洋,我火速辦了婚禮,結(jié)果婚禮上屎鳍,老公的妹妹穿的比我還像新娘宏娄。我一直安慰自己,他們只是感情好逮壁,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布孵坚。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卖宠。 梳的紋絲不亂的頭發(fā)上巍杈,一...
    開(kāi)封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音扛伍,去河邊找鬼筷畦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛刺洒,可吹牛的內(nèi)容都是我干的鳖宾。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼逆航,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鼎文!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起纸泡,我...
    開(kāi)封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤漂问,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后女揭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡栏饮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年吧兔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袍嬉。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡境蔼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伺通,到底是詐尸還是另有隱情箍土,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布罐监,位于F島的核電站吴藻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏弓柱。R本人自食惡果不足惜沟堡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望矢空。 院中可真熱鬧航罗,春花似錦、人聲如沸屁药。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至复亏,卻和暖如春绢彤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蜓耻。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工茫舶, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刹淌。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓饶氏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親有勾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子疹启,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348