在C语言库中有一系列的库函数和变量使得我们在编程中更加方便的以自定义的格式输出存在系统调用期间发生的错误。其中strerror和error函数是最常用的错误报告类库函数;变量program_invocatoin_short_name可以使你更加便利的获取发生错误的程序名。

1 char * strerror(int errnum)

该函数声明在string.h中,参数errnum通常取errno,函数会根据不同的errno值,返回指向特定错误消息的字符串指针。需要注意的是,你不可以私自修改这些字符串,而且如果后来有新的错误发生,这些字符串将被新的错误字符串所覆盖。

1.1 char *strerror_r(int errnum,char *buf,size_t n)

该函数作为GNU C的扩展,声明在string.h中。
因为strerror函数用来存储错误消息的内存是各进程共享的,所以随着后续错误的发生,它会不断被刷新覆盖。

为了弥补这种缺陷,我们可以使用strerror_r函数。它有三个参数,其中errnum代表错误代码,buf代表用户自定义的存储错误消息的缓存地址,n代表缓存大小。这样,在多进程编程中,我们就可以永久存储错误消息以供后续查看,而不需要担心被覆盖。

2 void * perror(const char * message)

该函数声明在stdio.h中,它向标准错误流stderr输出错误消息;

如果参数message为空或指向一个空字符串,则函数仅输出系统的错误消息;如果message不为空,则函数先输出参数指向的字符串,再添加一个冒号和空格符后,再输出系统错误消息。

program_invocation_name

strerror和perror函数产生完全相同的错误消息,而且描述的相当简单,仅有一行。有时候不能完全满足我们的需要。为此,我们引入了program_invocation_name 等变量。该变量等同于argv[0],表示不带目录的程序名。

另一个与他相似的变量为program_invocation_short_name, 它也同样代表了不含目录的程序名,只不过它更短,仅仅保留了最后一个'/'后的字符串。

#define _GNU_SOURCE

#include <error.h>
#define <stdio.h>
#define <stdlib.h>
#define <string.h>

FILE * open_sesam(char *file_name)
{
    FILE *stream;
    errno = 0;
    stream = fopen(file_name,"r");
    if(stream == NULL){
        fprintf(stderr,"%s:Couldn't open file %s:%s\n",\
 program_invocation_short_name,file_name,strerror(errno));
    exit(EXIT_FAILURE);
}
else
    return stream;
}

3 void error(int status,int errnum,const char *format,...)

有时候,我们在遇到一些错误时,并不是想让程序立即终止,而是希望它记下错误后,继续运行。此时就不得不用error函数了。

error首先输出程序名,默认通过全局变量program_name获得。但如果程序中,用户给全局函数指针变量error_print_program赋了非零值,那么error将自动通过它来调用用户自定义的函数来显示函数名;接着函数输出一个冒号加空格符,之后按照format格式输出用户自定义的字符串;如果errnum非0的话,接着函数再输出冒号加空格,之后再输出系统错误消息。

最后再来看看status参数。当它为非0时,error函数再输出完提示消息后,接着就调用exit函数返回status并退出。;如果status为0,则error函数会再输出完提示消息后正常返回,同时,全局变量error_message_count加1,程序并不终止。

3.1 void error_at_line(int status,int errnum,const char *fname,unsigned lineno,const char *format,...)

该函数与刚刚介绍的error函数非常类似,唯一的不同就是多了fname和lineno参数。它们的输出位置位于程序名之后,格式化字符串之前,主要作用是用来定位发生错误的位置。

这里又要介绍一个全局变量,error_one_per_line。它仅仅影响函数error_at_line。如果它被设置为非0值,那么当同一行发生多个错误时,文件名和行号将不会重复输出。

该函数的退出机制同error,在此就不在赘述。

下面看一个例子:

{
    char *line = NULL;
    size_t len = 0;
    unsigned lineno = 0;
    error_message_count = 0;
   while(! feof_unlocked(fp)){
        size_t n = getline(&line,&len,fp);
        if(n<=0)
            break;//End of file or error
        ++lineno;

/*process the line*/
...

    if(detected error in line)
        error_at_line(0,errno,filename,lineno,\
        "some error test %s",some_varible);
    }
    if(error_message_count != 0)
        error(EXIT_FAILURE,0,"%u errors found",error_message_count);
}

===========我是华丽的分割线===========


更多知识:
点击关注专题:嵌入式Linux&ARM

或浏览器打开:https://www.jianshu.com/c/42d33cadb1c1

或扫描二维码: