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中定义,用于获取错误码对应的消息描述。这两个函数在解析相应头文件时再进行分析。