errno.h
1. 简介
1.1 历史
UNIX对错误的系统调用采用一种简单的指示方式, 用汇编语言实现, 使用条件编码的进位标志来测试.
- 如果进位标志被清零, 则说明系统调用成功
- 如果进位标志不为零, 则说明系统调用错误
一个机器寄存器记录了一个很小的整数, 用来说明错误的性质
1.2 C中的错误处理
C采用一个具有外部连接的数据对象, 任何失败的系统调用都从内核中存储一个叫做errno的整型变量作为错误编码. 所以必须早点访问errno, 如果另一个系统调用也失败了, 原来的错误编码将会被后来的错误编码覆盖. 但一个成功的系统调用不会覆盖errno的错误编码.<errno.h>
头文件定义了整数变量errno, 它是通过系统调用设置的,在错误事件中表明了什么发生了错误.
1.3 数学错误
除了系统调用的错误, 数学错误也算入errno中, 可分为几类:
- 向上溢出: 数值太大导致结果不能作为指定类型的浮点值表示
- 向下溢出: 数值太小导致结果不能作为指定类型的浮点值表示
- 有效值丢失: 没有位置容纳结果类型指示的有效位
- 域错误: 接受一个指定的参数而结果没有被定义
但"有效位丢失"是一个不确定是否要报告的错误. 不同的程序员对于这个问题有不同的看法, 有些情况下有效位丢失并不是一个严重问题.
2. <errno.h>的使用
不同的系统对于错误编码的值设置不同, 如果需要为某个系统写代码, 那不得不去学习他的错误代码文档. 如果编写可移植代码, 则要避免任何附加的错误代码假设, 如下:
|
3. <errno.h>的实现
<errno.h>
的主要目的在于建立errno这个宏, 当调用其他库函数时, 如果出现错误则对这个宏进行修改, 覆盖为相应的错误编码. errno在程序启动时为0, 但不能被任何库函数设置为0.
/* errno.h standard header */ |
这里errno面临一个问题: 有时errno对于错误的说明过于模糊, 有时又过于清楚. 由于任何库函数都能对errno进行不同的修改, 所以唯一能依赖的只有C标准中明确规定的错误行为, 例如: 调用sqrt(-1)
就可以知道errno包含了EDOM值.
由于不同系统的错误编码不同, 所以部分库函数需要知道错误编码的有效范围, 或者一些特定的错误编码, 这时就需要<yvals.h>
来规范
|
errno.c确保errno初始化为0, 并#undef预处理指令来保证<errno.h>的安全性
/* errno storage */ |