PIGWORLD

学无止境

1.7 错误处理

1.7 错误处理

UNIX系统函数发生错误时,通常返回一个负值,并且整数errno被设置为一个可以给出额外信息的值。例如,open函数或者返回一个非负的文件描述符(当一切正常时),或者产生一个错误。一个open的错误能产生15个可能的errno值,例如文件不存在,权限问题,等等。一些函数不返回负值,而是使用习惯方法来表示错误。例如,多数函数返回一个对象的指针,而返回一个null(空)指针来表示一个错误。

头文件<errno.h>定义了标识符errnoerrno的每个可能的常量值。这之中的每个常量值都以字符E开头。在UNIX系统手册第二节的第一页,名为intro(2)的页面中,同样列出了这之中所有的错误常量。例如,如果errno等于常量EACCES,这就显示了一个权限错误,比如没有足够的权限来打开所请求的文件。

Linux中,错误常量被列举在手册errno(3)中。

POSIXISO Cerrno扩展定义为可变的整型左值。它既可以是一个包含了错误代码的整数,也可以是一个函数,该函数返回指向错误代码的指针。以前的定义是

 

extern int errno;

 

然而在一个支持线程的环境中,进程地址空间在多个线程中共享,同时每个线程都需要errno的本地拷贝来防止线程间互相影响。例如,Linux通过以下定义来支持多线程访问errno

 

extern int *_ _errno_location(void);

#define errno (*_ _errno_location())

 

errno有两条规则。第一,如果不发生错误,errno的值决不会被程序清除。因此,只有在函数的返回值表示错误发生时,才需要检查errno的值。第二,任何函数都不会把errno的值设置为0,同时在<errno.h>中也没有定义任何常量值为0

标准C中定义了两个函数来帮助打印错误消息。

 

#include <string.h>

char *strerror(int errnum);

返回值:指向消息字符串的指针

 

该函数把errno的典型值errnum映射到一个错误消息字符串,并返回一个指向字符串的指针。

perror函数在标准错误产生并返回一个错误消息,该消息基于errno的当前值。

 

#include <stdio.h>

void perror(const char *msg);

 

它输出msg指向的字符串,接着是一个分号和一个空格,然后是与errno值对应的错误消息,最后是一个新行。

例子

1.8展示了这两个函数的应用。

如果该程序被编译为文件a.out,我们将看到

 

$ ./a.out

EACCES: Permission denied

./a.out: No such file or directory

 

注意我们把程序名字argv[0]作为参数传递给perrorargv[0]的值是./a.out。这是UNIX系统的一个标准惯例。通过这样做,如果程序是作为管道的一部分执行,就像在

 

prog1 < inputfile | prog2 | prog3 > outputfile

 

我们就能够分清是三个程序中是哪个产生了错误消息。

 1#include "apue.h"
 2#include <errno.h>
 3
 4int
 5main(int argc, char *argv[])
 6{
 7    fprintf(stderr, "EACCES: %s\n", strerror(EACCES));
 8    errno = ENOENT;
 9    perror(argv[0]);
10    exit(0);
11}

1.8 strerrorperror的示范

本书中的所有的例子都使用附录B中的错误函数,来代替直接调用strerror或者perror。附录中的错误函数使用了ISO C的可变参数列表,可以只用单个C语句来处理错误情况。

错误恢复

<errno.h>中定义的错误可以被分为两类:致命的和非致命的。一个致命错误是不能够恢复的。最好的办法是在用户的屏幕上打印一条错误消息,或者在一个日志文件中写入错误消息,接着在退出。另一方面,非致命错误在某些时候能够更得体的处理。多数非致命错误是自然的临时错误,例如当系统的活动程序较少时,(系统)资源短缺的错误可能就不会发生。

资源相关的非致命错误包括EAGAINENFILEENOBUFSENOLCKENOSPCENOSREWOULDBLOCK,当ENOMEMEBUSH表示一个共享资源正在被使用时,它们也可以被作为非致命错误。某些时候,当EINTR中断了一个缓慢的系统调用时,它也可以被看作非致命错误(详见10.5节)。

资源相关的非致命错误的典型恢复动作就是延迟一会儿再试。这个技巧也能应用在其它循环中。例如,如果错误表示网络连接没有工作,那么程序可能会延迟一会儿再重新建立连接。一些程序使用指数增长的算法,每次等待更长的时间。

最后,由应用程序开发者来决定哪些错误是可以恢复的。如果一个合理的策略能够被用来恢复错误,通过避免异常退出,我们就可以增强我们程序的健壮性。

posted on 2006-01-09 22:58 PIGWORLD 阅读(668) 评论(1)  编辑 收藏 引用 所属分类: 《UNIX环境高级编程(第二版)》翻译

Feedback

# re: 1.7 错误处理 2006-03-30 09:40 Jerry

能不能把英文版发给我阿,谢谢!

jerry@2001tech.com
  回复  更多评论   



只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理