C标准库源码解剖(2):错误报告errno.h

    errno.h在/usr/include下,定义了存放错误码的全局变量errno,及错误码EDOM,ERANGE,EILSEQ。它包含了/usr/include/bits下的bits/errno.h头文件。bits/errno.h不是标准C库中的头文件,在Linux中它为错误码提供数值定义,对标准C中指定的错误码EDOM,ERANGE,EILSEQ定义具体的数值。
    bits/errno.h如下:

/* bits/errno.h: 错误报告常量 Linux专用的版本(/usr/include/bits/errno.h) */ #ifdef _ERRNO_H # undef EDOM # undef EILSEQ # undef ERANGE # include <linux/errno.h> /* Linux没有ENOTSUP错误码 */ # define ENOTSUP EOPNOTSUPP /* 早期的Linux版本也没有ECANCELED错误码 */ # ifndef ECANCELED # define ECANCELED 125 # endif /* 支持健壮锁机制的错误码 */ # ifndef EOWNERDEAD # define EOWNERDEAD 130 # define ENOTRECOVERABLE 131 # endif # ifndef __ASSEMBLER__ /* 获取全局变量errno的地址的函数 */ extern int *__errno_location (void) __THROW __attribute__ ((__const__)); # if !defined _LIBC || defined _LIBC_REENTRANT /* 当使用线程时,errno是一个单线程变量 */ # define errno (*__errno_location ()) # endif # endif /* !__ASSEMBLER__ */ #endif /* _ERRNO_H */ #if !defined _ERRNO_H && defined __need_Emath /* 这个虽然丑陋,但内核并不是完全干净的。在__need_Emath被定义的情况下,我们必须只定义 EDOM,EILSEQ和ERANGE的值 */ # define EDOM 33 /* 参数不在数学函数能接受的范围内 */ # define EILSEQ 84 /* 非法的字节顺序,在翻译多字节字符序列时遇到的编码错误 */ # define ERANGE 34 /* 数学函数的结果超出范围 */ #endif /* !_ERRNO_H && __need_Emath */

    标准C的errno.h头文件如下:

/* ISO C99 Standard: 7.5 错误报告 <errno.h> */ #ifndef _ERRNO_H /* 预处理器如果只需要EDOM和ERANGE的定义,不需要其他任何的错误码, 则它会定义__need_Emath宏 */ #ifndef __need_Emath # define _ERRNO_H 1 # include <features.h> /* 定义了一些表示编译选项的宏 */ #endif __BEGIN_DECLS /* 从依赖于系统的文件中获取错误码常量,这个依赖于系统的文件将会测试__need_Emath 和_ERRNO_H */ #include <bits/errno.h> #undef __need_Emath #ifdef _ERRNO_H /* 定义全局变量errno,除非它被bits/errno.h定义成了一个宏。 在GNU中,它是一个单线程的变量。有这个重新定义时errno宏仍然可以工作,但现在 它将成为一个没有原型的函数声明,可能会触发一个-W-Wstrict-prototypes警告 */ #ifndef errno extern int errno; #endif #ifdef __USE_GNU /* 程序被调用时会带有这些变量,它们在基于ARGV[0]的值来启动程序(仅当你使用GNU ld程序) 时会自动被设置 */ extern char *program_invocation_name, *program_invocation_short_name; #endif /* __USE_GNU */ #endif /* _ERRNO_H */ __END_DECLS #endif /* _ERRNO_H */ /* 有一些<bits/errno.h>中定义了error_t作为一个枚举类型,这样在调试器里打印error_t的 值时就可以显示其名称。即使前面包含了<bits/errno.h>,有时我们还是需要定义一下 */ #if defined __USE_GNU || defined __need_error_t # ifndef __error_t_defined typedef int error_t; # define __error_t_defined 1 # endif # undef __need_error_t #endif

    解释:
    (1)C标准规定了必须定义错误码EDOM,EILSEQ,ERANGE,其值可以由系统自行指定,在Linux中它们分别为33、84、34。
    (2)EDOM表示参数不在数学函数能接受的范围内;EILSEQ表示非法的字节顺序,在翻译多字节字符序列时遇到的编码错误;ERANGE表示数学函数的结果超出范围。程序产生相应错误时全局变量errno会保存对应的错误码。
    (3)__BEGIN_DECLS/__END_DECLS宏用来表示数据结构及函数原型声明的开始和结束。这类似于MFC中的BEGIN_MESSAGE_MAP/END_MESSAGE_MAP。
    还有两个错误处理函数perror和strerror。perror在stdio.h中定义,用于打印错误码及其消息描述;strerror在string.h中定义,用于获取错误码对应的消息描述。这两个函数在解析相应头文件时再进行分析。

你可能感兴趣的:(C标准库源码解剖(2):错误报告errno.h)