《UNIX环境高级编程(第3版)》——1.7 出错处理

1.7 出错处理

当UNIX系统函数出错时,通常会返回一个负值,而且整型变量errno通常被设置为具有特定信息的值。例如,open函数如果成功执行则返回一个非负文件描述符,如出错则返回1。在open出错时,有大约15种不同的errno值(文件不存在、权限问题等)。而有些函数对于出错则使用另一种约定而不是返回负值。例如,大多数返回指向对象指针的函数,在出错时会返回一个null指针。

文件中定义了errno以及可以赋与它的各种常量。这些常量都以字符E开头。另外,UNIX系统手册第2部分的第1页,intro(2)列出了所有这些出错常量。例如,若errno等于常量EACCES,表示产生了权限问题(例如,没有足够的权限打开请求文件)。

在Linux中,出错常量在errno(3)手册页中列出。
POSIX和ISO C将errno定义为一个符号,它扩展成为一个可修改的整形左值(lvalue)。它可以是一个包含出错编号的整数,也可以是一个返回出错编号指针的函数。以前使用的定义是:

extern int errno;

但是在支持线程的环境中,多个线程共享进程地址空间,每个线程都有属于它自己的局部errno以避免一个线程干扰另一个线程。例如,Linux支持多线程存取errno,将其定义为:

extern int *__errno_location(void);
 #define errno (*__errno_location())

对于errno应当注意两条规则。第一条规则是:如果没有出错,其值不会被例程清除。因此,仅当函数的返回值指明出错时,才检验其值。第二条规则是:任何函数都不会将errno值设置为0,而且在中定义的所有常量都不为0。

C标准定义了两个函数,它们用于打印出错信息。

#include <string.h>

char *strerror(int errnum);
                       返回值:指向消息字符串的指针

strerror函数将errnum(通常就是errno值)映射为一个出错消息字符串,并且返回此字符串的指针。

perror函数基于errno的当前值,在标准错误上产生一条出错消息,然后返回。

#include <stdio.h> 

void perror(const char *msg);

它首先输出由msg指向的字符串,然后是一个冒号,一个空格,接着是对应于errno值的出错消息,最后是一个换行符。

实例
图1-8程序显示了这两个出错函数的使用方法。

#include "apue.h"
#include <errno.h>

int
main(int argc, char *argv[])
{
   fprintf(stderr, "EACCES: %s\n", strerror(EACCES));
   errno = ENOENT;
   perror(argv[0]);
   exit(0);
}

图1-8 例示strerror和perror

如果将此程序编译成文件a.out,然后执行它,则有

$ ./a.out
EACCES: Permission denied
./a.out: No such file or directory

注意,我们将程序名(argv[0],其值是./a.out)作为参数传递给perror。这是一个标准的UNIX惯例。使用这种方法,在程序作为管道的一部分执行时,例如:

prog1 < inputfile | prog2 | prog3 > outputfile
我们就能分清3个程序中的哪一个产生了一条特定的出错消息。

本书中的所有实例基本上都不直接调用strerror或perror,而是使用附录B中的出错函数。该附录中的出错函数使我们只用一条C语句就可利用ISO C的可变参数表功能处理出错情况。

出错恢复
可将在中定义的各种出错分成两类:致命性的和非致命性的。对于致命性的错误,无法执行恢复动作。最多能做的是在用户屏幕上打印出一条出错消息或者将一条出错消息写入日志文件中,然后退出。对于非致命性的出错,有时可以较妥善地进行处理。大多数非致命性出错是暂时的(如资源短缺),当系统中的活动较少时,这种出错很可能不会发生。

与资源相关的非致命性出错包括:EAGAIN、 ENFILE、 ENOBUFS、 ENOLCK、 ENOSPC、 EWOULDBLOCK,有时ENOMEM也是非致命性出错。当EBUSY指明共享资源正在使用时,也可将它作为非致命性出错处理。当EINTR中断一个慢速系统调用时,可将它作为非致命性出错处理(在10.5节对此会进行更多说明)。

对于资源相关的非致命性出错的典型恢复操作是延迟一段时间,然后重试。这种技术可应用于其他情况。例如,假设出错表明一个网络连接不再起作用,那么应用程序可以采用这种方法,在短时间延迟后,尝试重建该连接。一些应用使用指数补偿算法,在每次迭代中等待更长时间。

最终,由应用的开发者决定在哪些情况下应用程序可以从出错中恢复。如果能够采用一种合理的恢复策略,那么可以避免应用程序异常终止,进而就能改善应用程序的健壮性。

时间: 2024-11-05 06:08:19

《UNIX环境高级编程(第3版)》——1.7 出错处理的相关文章

ubuntu-最近在学习Unix 环境高级编程,配置环境时遇到了些问题

问题描述 最近在学习Unix 环境高级编程,配置环境时遇到了些问题 最近再看APUE(UNix 环境高级编程)的第三版,照着教程在中配置环境.也就是想要运行书中的源码,则要安装 libbsd-dev包,而每次安装这个包时,都如上报错,请问各位大虾,该怎么解决呢? 解决方案 你好, 类似的问题我也遇到过 ubuntu下apt-get install安装软件, 报"无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系",今天终于找到解决方法了. 一般出现这种情况的原

Mac OS X 10.8 中编译APUE(Unix环境高级编程)的源代码过程_C 语言

最近在温习APUE(<unix环境高级编程>),以前都是在linux下搞,现在打算在自己机器弄下,于是google了下,把编译的事情搞定了,修改了一些教程的一些错误,比如下载链接之类的. 1.下载源文件,我这里是第二版,貌似第三版的英文版出来了... 复制代码 代码如下: wget http://www.apuebook.com/src.2e.tar.gz 2.解压 复制代码 代码如下: tar zxf src.2e.tar.gz 3.修改些东西 复制代码 代码如下: cd apue.2e/

UNIX环境高级编程---标准I/O库

前言:我想大家学习C语言接触过的第一个函数应该是printf,但是我们真正理解它了吗?最近看Linux以及网络编程这块,我觉得I/O这块很难理解.以前从来没认识到Unix I/O和C标准库I/O函数压根不是一码事.Unix I/O也叫低级I/O,也叫Unbuffered I/O,是操作系统内核部分,也是系统调用:而C标准I/O函数相对也成Buffered I/O,高级I/O,一般是为了效率考虑对这些系统调用的封装.以前使用getchar()经常为输入完后的回车而出错.那是不理解标准I/O实现时的

UNIX环境高级编程中的apue.h

/************** * *apueerror.h * *************/ #include <apue.h> #include <stdio.h> #include <errno.h> /* for definition of errno */ #include <stdarg.h> /* ISO C variable aruments */ static void err_doit(int, int, const char *, va

unix高级编程-UNIX环境高级编程 times() 疑问

问题描述 UNIX环境高级编程 times() 疑问 例程 int main(int argc, char *argv[]) { clock_t s_clk,e_clk; struct tms s_tms,e_tms; s_clk = times(&s_tms); system("ls /dev"); system("date"); sleep(1); e_clk = times(&e_tms); printf("e_clk %ld - s

unix环境高级编程-UNIX环境高级编程源代码对应

问题描述 UNIX环境高级编程源代码对应 今天开始学习UNIX环境高级编程,书中的源代码下载到了,但是发现根本不是按章节来的,找起来是相当的费时间,有哪位大神用过后知道他们的对应关系么,比如1-1对应ls1.c这样,真是万分感激,造福大家啊!

《UNIX环境高级编程(第3版)》——2.3 UNIX系统实现

2.3 UNIX系统实现 上一节说明了3个由各自独立的组织所制定的标准:ISO C.IEEE POSIX以及Single UNIX Specification.但是,标准只是接口的规范.这些标准是如何与现实世界相关连的呢?这些标准由厂商采用,然后转变成具体实现.本书中我们不仅对这些标准感兴趣,还对它们的具体实现感兴趣. 在McKusick等[1996]的1.1节中给出了UNIX系统家族树的详细历史.UNIX的各种版本和变体都起源于在PDP-11系统上运行的UNIX分时系统第6版(1976年)和第

《UNIX环境高级编程(第3版)》——2.5 限制

2.5 限制 UNIX系统实现定义了很多幻数和常量,其中有很多已被硬编码到程序中,或用特定的技术确定.由于大量标准化工作的努力,已有若干种可移植的方法用以确定这些幻数和具体实现定义的限制.这非常有助于改善UNIX环境下软件的可移植性. 以下两种类型的限制是必需的. (1)编译时限制(例如,短整型的最大值是什么?) (2)运行时限制(例如,文件名有多少个字符?) 编译时限制可在头文件中定义.程序在编译时可以包含这些头文件.但是,运行时限制则要求进程调用一个函数获得限制值. 另外,某些限制在一个给定

《UNIX环境高级编程(第3版)》——第1章 UNIX基础知识 1.1 引言

第1章 UNIX基础知识 1.1 引言 所有操作系统都为它们所运行的程序提供服务.典型的服务包括:执行新程序.打开文件.读文件.分配存储区以及获得当前时间等,本书集中阐述不同版本的UNIX操作系统所提供的服务. 想要按严格的先后顺序介绍UNIX,而不超前引用尚未介绍过的术语,这几乎是不可能的(可能也会令人厌烦).本章从程序员的角度快速浏览UNIX,对书中引用的一些术语和概念进行简要的说明并给出实例.在以后各章中,将对这些概念做更详细的说明.对于初涉UNIX环境的程序员,本章还简要介绍了UNIX提

UNIX环境高级编程:线程同步之互斥锁、读写锁和条件变量

一.使用互斥锁 1.初始化互斥量 pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥量 int pthread_mutex_init(pthread_mutex_t*mutex,pthread_mutexattr_t*attr);//动态初始化互斥量 int pthread_mutex_destory(pthread_mutex_t*mutex);//撤销互斥量 不能拷贝互斥量变量,但可以拷贝指向互斥量的指针,这样就可以使多个函数