首页 > 编程 > .NET > 正文

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

2024-07-10 13:27:14
字体:
来源:转载
供稿:网友

  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如下:

 

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

 

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

 

[cpp] view plaincopy
  1. /* ISO C99 Standard: 7.5  错误报告   <errno.h> */  
  2. #ifndef _ERRNO_H  
  3. /* 预处理器如果只需要EDOM和ERANGE的定义,不需要其他任何的错误码, 
  4.     则它会定义__need_Emath宏 */  
  5. #ifndef __need_Emath  
  6. # define _ERRNO_H   1  
  7. # include <features.h>  /* 定义了一些表示编译选项的宏 */  
  8. #endif  
  9. __BEGIN_DECLS  
  10. /* 从依赖于系统的文件中获取错误码常量,这个依赖于系统的文件将会测试__need_Emath 
  11.     和_ERRNO_H */  
  12. #include <bits/errno.h>   
  13. #undef  __need_Emath  
  14. #ifdef  _ERRNO_H  
  15. /* 定义全局变量errno,除非它被bits/errno.h定义成了一个宏。 
  16.     在GNU中,它是一个单线程的变量。有这个重新定义时errno宏仍然可以工作,但现在 
  17.     它将成为一个没有原型的函数声明,可能会触发一个-W-Wstrict-prototypes警告 */  
  18. #ifndef errno    
  19. extern int errno;   
  20. #endif  
  21. #ifdef __USE_GNU  
  22. /* 程序被调用时会带有这些变量,它们在基于ARGV[0]的值来启动程序(仅当你使用GNU ld程序) 
  23.     时会自动被设置 */  
  24. extern char *program_invocation_name, *program_invocation_short_name;  
  25. #endif /* __USE_GNU */  
  26. #endif /* _ERRNO_H */  
  27. __END_DECLS  
  28. #endif /* _ERRNO_H */  
  29.  /* 有一些<bits/errno.h>中定义了error_t作为一个枚举类型,这样在调试器里打印error_t的 
  30.      值时就可以显示其名称。即使前面包含了<bits/errno.h>,有时我们还是需要定义一下 */  
  31. #if defined __USE_GNU || defined __need_error_t  
  32. # ifndef __error_t_defined  
  33. typedef int error_t;    
  34. #  define __error_t_defined 1  
  35. # endif  
  36. # undef __need_error_t  
  37. #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中定义,用于获取错误码对应的消息描述。这两个函数在解析相应头文件时再进行分析。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表