1. 出错处理
1.1关于errno
当UNIX出错时,常常返回一个负值,且errno通常被设置为含附加信息的一个值。当然有些函数不返回负值而使用另外的约定(有些返回NULL指针)。
文件<errno.h>中定义了各种errno常量,可以通过名字反映其绑定的出错信息(UNIX在intro(2)——即man 2 intro,linux在errno(3)中列出),当然在多线程环境中,每个线程又都拥有属于自己的局部errno(使用宏定义为含线程信息的一变量)。
1.2 errno规则
对于errno需知两大规则:
(1) 若没出错,其值不会被一例程清除,即仅当函数返回出错时才会检验其值;
(2) 任意函数均不会将其设置为0,即errno常量均不为0
1.3 错误处理函数
(1) #include<string.h>
char* strerror(int errnum)
将errno映射为出错信息字符串并返回其指针。
(2) #include<stdio.h>
void perror(const char* msg)
首先输出msg指向字符串,然后一个空格,一个冒号,接着是对应于errno的出错信息,最后一个换行符。
1.4 出错恢复
在<errno.h>中定义的出错可分为两种:致命性与非致命性的。致命性只能打印出错信息,非致命性错误很多只是暂时的,有时可以进行妥善的处理。
与资源有关的非致命性出错一般恢复动作是延迟一些时候再试一次。这种技术也可用于其他情况,当然最终的决策权在开发者手里,他们可以提高整个系统的健壮性。
2. 信号和系统调用
2.1 信号
信号时通知进程易发生某种情况的技术。而进程如何日处理这种技术有三种选择:
(1) 忽略该信号。有些信号表示硬件异常(除0)等,因为他们产横的后果不确定,所以不推荐使用;
(2) 按系统默认方式处理。(除0系统默认终止进程)
(3) 提供同一个函数与信号绑定,当信号发生时调用该函数(捕捉函数)
很多情况会产生信号,当然也可以调用一函数一向另一进程发送信号,当然前提是该进程是超级进程。
2.2 系统调用
用户进程可以直接调用系统调用,也可以调用库函数,而很多库函数功能的实现则需要调用一些系统调用,因而系统调用并不仅仅为用户服务,而库函数则是方便用户的使用而事先写好的。
3. UNIX标准及实现
4. 限制
UNIX系统的实现定义了很多的幻数(数字含义与意图不明)与常量,已有若干种可移植的方法用于确定幻数以及实现定义的限制。
限制必须包含以下两种类型:
(1) 编译时限制(例如某种数据类型的长度是所少等)
(2) 运行时限制(例如文件名可包含多少字符等)
编译时限制刻在某文件中进行定义,编译时包含这些头文件即可,而运行时限制则要求进程调用另一函数动态获取此限制值。
为解决不同文件系统间限制定义不同的问题,提供了以下三种限制:
(1) 编译时限制(头文件)
(2) 不与文件和目录相关联的运行时限制(sysconf函数)
(3) 与文件和目录相关联的运行时限制(pathconf和fpathconf函数)
4.1 ISO C 限制
其定义的都是编译时限制,整型相关均定义在头文件<limits.h>中,<float.h>中定义了一些关于浮点类型的定义。
经常见到的还有FOPEN_MAX定义为可同时打开的I/O标准流的最小数量,定义在<stdio.h>中,其值为8。POSIX.1中STREAM_MAX必须与FOPEN_MAX同值(若已定义)。
<stdio.h>还定义了TMP_MAX,定义为由函数tmpnam产生的唯一文件名的个数
4.2 POSIX限制
定义了很多涉及操作系统实现的常量,其中与POSIX接口有关的部分常量被分为以下五类:
(1) 不变的最小值(<limits.h>中的19个常量)
(2) 不变值:SSIZE_MAX
(3) 运行时刻增加的值
(4) 运行时不变的值
(5) 路径名可变值
4.3 XSI限制
定义常量被分为以下三类:
(1) 不变的最小值(<limits.h>中的10个常量)
(2) 数值限制:LONG_BIT和WORD_BIT
(3) 运行时不变值(可能不确定)
4.4 基本系统数据类型
头文件<sys/types.h>定义了与实现有关的数据类型,还有很多定义在其他头文件内。