Linux系统调用API容错机制

来源:互联网 发布:access录入数据 编辑:程序博客网 时间:2024/06/15 06:29

以open函数为例,该系统API原型为:

int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);

在c语言中,是不可能存在相同函数名的两个函数的,那么可以知道open函数是一个可变参函数,即

open(const char *pathname, int flags, ...)

当flags取值含O_CREAT(文件不存在则创建)值时,可变参用来指定新建的该文件的属性。
根据man手册介绍,open的返回值及容错机制都有说到

open() and creat() return the new file descriptor, or -1 if an error occurred (in which case, errno is set appropriately).

即open()和create()函数如果执行成功就返回该文件的文件描述符,失败则返回-1,失败的原因会被记录在errno中。再往手册下看,可以看到errno的取值,有EACCES,EEXIST,EFAULT,EFBIG等等。可以推测,这些取值是一些宏定义。该API都退出了,还可以打印errno的值来得到错误标识码,所以这些量肯定是全局变量。既然如此,那么这个errno肯定是不可重入的,也就是说它记录的是最近一次API调用的错误码。
这些宏的定义在/usr/include/asm-generic/errno-bash.h中:

#define EPERM        1  /* Operation not permitted */#define ENOENT       2  /* No such file or directory */#define ESRCH        3  /* No such process */#define EINTR        4  /* Interrupted system call */#define EIO          5  /* I/O error */#define ENXIO        6  /* No such device or address */#define E2BIG        7  /* Argument list too long */#define ENOEXEC      8  /* Exec format error */#define EBADF        9  /* Bad file number */#define ECHILD      10  /* No child processes */#define EAGAIN      11  /* Try again */#define ENOMEM      12  /* Out of memory */#define EACCES      13  /* Permission denied */#define EFAULT      14  /* Bad address */#define ENOTBLK     15  /* Block device required */#define EBUSY       16  /* Device or resource busy */#define EEXIST      17  /* File exists */#define EXDEV       18  /* Cross-device link */#define ENODEV      19  /* No such device */#define ENOTDIR     20  /* Not a directory */#define EISDIR      21  /* Is a directory */#define EINVAL      22  /* Invalid argument */#define ENFILE      23  /* File table overflow */#define EMFILE      24  /* Too many open files */#define ENOTTY      25  /* Not a typewriter */#define ETXTBSY     26  /* Text file busy */#define EFBIG       27  /* File too large */#define ENOSPC      28  /* No space left on device */#define ESPIPE      29  /* Illegal seek */#define EROFS       30  /* Read-only file system */#define EMLINK      31  /* Too many links */#define EPIPE       32  /* Broken pipe */#define EDOM        33  /* Math argument out of domain of func */#define ERANGE      34  /* Math result not representable */

测试代码: 可读可写打开当前目录的errno_test文件,但是当前目录并不存在该文件或者目录

int main(void){    int fd;    fd = open("./errno_test", O_RDWR);    if (fd < 0)    {        printf("errno: %d\n", errno);    }    close(fd);    return 0;}

运行结果:
这里写图片描述
错误码2对应到宏是ENOENT,上面注释也已说明: “No such file or directory”。
对于API使用者来说,一个错误标识码表达错误信息显然还不够对明朗,每次拿到标注码后还要去对照宏定义(的注释内容)显然十分不方便。既然这些标识码有与之对应的错误信息,何不将他们封装成一个指针数组,指针指向错误信息字符串?这样每次拿到错误标注码后就可以作为下标索引得到数组中的错误信息了。
当然,这么简单是事情,标准c库的perror函数已经为我们实现了:

int main(void){    int fd;    fd = open("./errno_test", O_RDWR);    if (fd < 0)    {        //printf("errno: %d\n", errno);        perror("open");    }    close(fd);    return 0;}

运行结果:
这里写图片描述
perror的用法,也十分巧妙。
Linux API的这种设计方法,值得我们在项目开发中借鉴。

0 0