国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
第三篇:errno.h快速入門

簡(jiǎn)介:

頭文件errno.h定義了一個(gè)全局的宏errno,它被展開為一個(gè)int類型的“左值”,這意味著宏errno不一定是個(gè)對(duì)象的標(biāo)識(shí)符,也可以展開為一個(gè)由函數(shù)返回的可以修改的“左值”,比如int*errno(),這個(gè)后面會(huì)講,你可以暫且把它理解為一個(gè)全局的int型變量(雖然這樣理解是錯(cuò)的,不過(guò)方便理解)。

簡(jiǎn)單來(lái)說(shuō),errno.h只是為了提供了一種錯(cuò)誤報(bào)告機(jī)制。比如,一個(gè)函數(shù)調(diào)用fopen()發(fā)生了錯(cuò)誤,它可能就會(huì)去修改errno的值,這樣外部的代碼可以通過(guò)判斷errno的值來(lái)區(qū)分fopen()內(nèi)部執(zhí)行時(shí)是否發(fā)生錯(cuò)誤,并根據(jù)errno值的不同來(lái)確定具體的錯(cuò)誤類型。
先來(lái)看一段代碼,Demo1:

01 #include    <stdio.h>
02 #include    <errno.h>
03  
04 int main ( int argc, char *argv[] )
05 {
06     //try to open file "whatever.txt". when you run this demo,make sure the file is NOT existed..。
07     FILE *fp = fopen("whatever.txt","r");
08  
09     if(fp ==NULL)
10     {
11         printf("Can not open file\n");
12  
13         printf("errno value: %d, it means: %s",errno, strerror(errno));
14     }
15  
16     return 0;
17 }

程序會(huì)輸出:

1 Can not open file
2 errno value: 2, it means: No such file or directory

strerror是標(biāo)準(zhǔn)庫(kù)stdio.h定義的一個(gè)函數(shù),它用來(lái)返回錯(cuò)誤代碼所代表的含義。如Demo1所示,我們用fopen(也在stdio.h中定義)打開一個(gè)并不存在的文件,因此返回的fp是一個(gè)空指針。而在fopen嘗試打開文件失敗時(shí)會(huì)修改errno的值,Demo1里fopen失敗原因是文件不存在,因此fopen將會(huì)把errno指向的值修改為2,通過(guò)stderror可以看到錯(cuò)誤代碼2的意思是“No suchfile or directory”。

帥氣,看起來(lái)用errno來(lái)報(bào)告錯(cuò)誤,既方便,也很簡(jiǎn)單,但實(shí)際應(yīng)用時(shí)遠(yuǎn)沒(méi)Demo1那么簡(jiǎn)單,試下Demo2:

01 #include    <stdio.h>
02 #include    <errno.h>
03 #include    <math.h> 
04  
05 int main ( int argc, char *argv[] )
06 {
07     /*try to open file "whatever.txt". when you run this demo,make sure the file is NOT existed...*/
08     FILE *fp = fopen("whatever.txt","r");
09  
10     if(fp ==NULL)
11     {
12         printf("Can not open file\n");
13  
14         int root = sqrt(123568 -123668 );
15  
16         printf("errno value: %d, it means: %s",errno, strerror(errno));
17     }
18  
19     return 0;
20 }

程序會(huì)輸出:

1 Can not open file
2 errno value: 33, it means: Numerical argument out of domain

這跟我們期望的錯(cuò)誤信息完全不一樣,因?yàn)閟qrt函數(shù)在得到一個(gè)非法的參數(shù)時(shí),它把errno的值修改成了33,覆蓋了fopen設(shè)置的錯(cuò)誤代碼。所以,使用errno一個(gè)比較安全的編碼方式是,在下個(gè)庫(kù)函數(shù)調(diào)用之前就查看它的值,千萬(wàn)不要因?yàn)槟硞€(gè)庫(kù)函數(shù)看似很簡(jiǎn)單就假設(shè)它不會(huì)修改errno的值,那樣會(huì)死的很慘……如果必須在查看errno之前調(diào)用別的庫(kù)函數(shù),一種安全的方式是先把errno的值保存到一個(gè)臨時(shí)變量里,然后調(diào)用那個(gè)“必須”調(diào)用的庫(kù)函數(shù),處理完畢后再把errno恢復(fù)到之前的值。如Demo3:

01 #include    <stdio.h>
02 #include    <errno.h>
03 #include    <math.h> 
04  
05 double getSqrt(double value)
06 {
07     //1、save last errno to a temp variable
08     int tmpErrno = errno;
09     //2、set errno to 0
10     errno = 0;
11  
12     double root = sqrt(123568 -123668 );
13  
14     printf("I changed errno to '%d' sliently...but it's safe \n",errno);
15  
16     //3.restore errno
17     errno = tmpErrno;
18  
19     return root;
20 }
21  
22 int main ( int argc, char *argv[] )
23 {
24     FILE *fp = fopen("whatever.txt","r");
25  
26     if(fp ==NULL)
27     {
28         printf("Can not open file\n");
29  
30         getSqrt(-1);
31  
32         printf("errno value: %d, it means: %s",errno, strerror(errno));
33     }
34  
35     return 0;
36 }

程序會(huì)輸出:

1 Can not open file
2 I changed errno to '33' sliently...but it's safe
3 errno value: 2, it means: No such file or directory

現(xiàn)在,就像期望的那樣輸出了。
但是……
這樣真的安全么?!想像一下,如果errno是個(gè)全局變量,那多線程環(huán)境下豈不完蛋了?!本來(lái)線程A把errno設(shè)置成2,還沒(méi)執(zhí)行到查看錯(cuò)誤的語(yǔ)句時(shí),線程B就把errno設(shè)置成了33,然后線程A才開始查看errno并輸出錯(cuò)誤信息,而這時(shí)輸出的錯(cuò)誤就很讓人抓狂了!神呀,這破東西多線程沒(méi)法兒用哇!
但是……
你多慮了……文章開始說(shuō)過(guò),宏errno可以被展開為一個(gè)“左值”,比如int*getYourErrno(),所以你可以在getYourErrno()里返回一個(gè)線程內(nèi)的局部變量,這樣不管哪個(gè)線程修改errno都修改的它自己的局部變量,所以我們擔(dān)心的問(wèn)題是不存在的??聪耬rrno.h的源碼就明白了

01 /* Get the error number constants from the system-specific file.
02    This file will test __need_Emath and _ERRNO_H.  */
03 #include <bits/errno.h>
04 #undef  __need_Emath
05  
06 #ifdef  _ERRNO_H
07  
08 /* Declare the `errno' variable, unless it's defined as a macro by
09    bits/errno.h.  This is the case in GNU, where it is a per-thread
10    variable.  This redeclaration using the macro still works, but it
11    will be a function declaration without a prototype and may trigger
12    a -Wstrict-prototypes warning.  */
13 #ifndef errno
14 extern int errno;
15 #endif

上面的注釋說(shuō)了,如果errno沒(méi)有定義過(guò)就把errno定義為“extern interrno;”,如果這樣多線程時(shí)是會(huì)發(fā)生悲劇的,先不著急哭,我們?nèi)デ懊婵纯此欠癖欢x過(guò),前面的代碼include了一個(gè)叫bits/errno.h的頭文件,看名字就很“險(xiǎn)惡”,進(jìn)去看看:

1 # ifndef __ASSEMBLER__
2 /* Function to get address of global `errno' variable.  */
3 extern int *__errno_location (void) __THROW __attribute__ ((__const__));
4  
5 #  if !defined _LIBC || defined _LIBC_REENTRANT
6 /* When using threads, errno is a per-thread value.  */
7 #   define errno (*__errno_location ())
8 #  endif
9 # endif /* !__ASSEMBLER__ */

果然來(lái)者不善……如果沒(méi)定義宏__ASSEMBLER__,就會(huì)執(zhí)行中間的代碼,里面的代碼又說(shuō)了,如果你沒(méi)定義_LIBC或者定義了_LIBC_REENTRANT他們就會(huì)把errno定義為__errno_location,一看到宏_LIBC_REENTRANT里面有“reentrant(重入)”就知道它不是個(gè)好東西……不是,是看到它的名字就知道它是跟多線程有關(guān)的,所以如果要在多線程環(huán)境下正確的使用errno,你需要確保__ASSEMBLER__沒(méi)有被定義,而且_LIBC沒(méi)被定義或者定義了_LIBC_REENTRANT。
可以寫個(gè)程序看下自己開發(fā)環(huán)境里這幾個(gè)宏的設(shè)置:

01 #include <stdio.h>
02 #include <errno.h>
03  
04 int main( void )
05 {
06 #ifndef __ASSEMBLER__
07         printf( "__ASSEMBLER__ is NOT defined!\n" );
08 #else
09         printf( "__ASSEMBLER__ is defined!\n" );
10 #endif
11  
12 #ifndef __LIBC
13         printf( "__LIBC is NOT defined\n" );
14 #else
15         printf( "__LIBC is defined!\n" );
16 #endif
17  
18 #ifndef _LIBC_REENTRANT
19         printf( "_LIBC_REENTRANT is NOT defined\n" );
20 #else
21         printf( "_LIBC_REENTRANT is defined!\n" );
22 #endif
23  
24         return 0;
25 }

我的輸出:

1 _ASSEMBLER__ is NOT defined!
2 __LIBC is NOT defined!
3 _LIBC_REENTRANT is NOT defined!

哈!看來(lái)我可以在多線程下安全的使用errno,如果你的默認(rèn)環(huán)境不可以就在makefile里定義上_LIBC_REENTRANT吧!
ok,有關(guān)errno.h的介紹到此就結(jié)束,休息,休息一下!

作者:Yao
來(lái)源:http://blog.yaohuiji.com/
歡迎轉(zhuǎn)載!作者期望轉(zhuǎn)載時(shí)帶上原文鏈接,不過(guò)這不是必須的。但務(wù)必在文章標(biāo)題處標(biāo)明【轉(zhuǎn)載】
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
c語(yǔ)言如何將printf產(chǎn)生的數(shù)據(jù)寫到txt文件中
經(jīng)典程序100例(91-100)
C語(yǔ)言文件操作之----文件的讀寫
UC頭條:Linux基礎(chǔ)IO[文件操作]
輸入輸出函數(shù)及控制流程語(yǔ)句
經(jīng)典C語(yǔ)言程序設(shè)計(jì)100例81-90
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服