zoukankan      html  css  js  c++  java
  • glibc_error reporting

      很多GNU C库里的函数都会侦测并报告错误条件。我们的程序需要检测这些错误条件。比如:我们打开一个输入文件时需要判断该文件是否正确的打开。如果没有正确打开,我们需要打印错误或者采取其他正确的方式。为了利用这种错误报告机制,我们需要包含头文件errno.h

    检测错误:

      很多库函数都会返回一个特殊的值来显示函数运行出错。常见的特殊值有:-1、空指针、EOF常量。但是这些返回值只能告诉你有错误产生,但不会告诉你错误是什么。如果你想知道错误是什么,就得靠错误代码,错误代码存储在变量errno中(在errno.h中有声明)

      errno变量包含了系统错误代码,其类型是volatile。该类型意味着其可以突然被异步线程改变,编译器从不假设其值。如果你在写信号处理程序应当保存改变量的值并恢复其值。

      errno的初始值为0,遇到错误时,errno绝无可能为0。但没有错误的时候,errno也不一定为0(库函数在成功运行时并不会修改errno的值)。所以,不要依据errno的值来判断错误是否发生。正确的做法是为每一个函数做好文档,标注出错误代码的值对应的错误类型。这样调用失败时,你可以通过检查errno获取错误代码,然后查询函数文档获取错误详情。如果你想获取某一库函数的错误代码,最好再次之前设置errno为0(或许你还想先保存以下errno的值,然后便于恢复该值)。

      每一个错误代码都有一个以E开头紧跟大写字母或数字的符号名,实际为定义在errno.h中的宏。当然不是所有的宏都定义在一个errno.h中(详细的可以自己翻一翻头文件,注意不仅仅只有一个errno.h,多个errno.h共同定义了全部的宏)

      错误代码的值一般为正数并且都不相同,但也有一个例外:EWORLDBLOCK和EAGAIN的错误代码是一样的。除了EWORLDBLOCK和EAGAIN,你可以使用switch语句来判断错误代码。但你不应该依赖于此,你唯一可以相信的就是文档。

      除了GNU/Hurd系统,几乎所有的系统调用被传入一个无效指针时都会返回EFAULT。所以呢,glibc的函数库说明文档中往往会省略对EFAULT的解释。

      大多数的错误代码宏名都显而易见的好懂,如果实在不知其意可以查看手册或者

    ~# man errno

    这里简单提几个宏:

    Macro: int EDOM
        域错误,可以理解为定义域错误。主要用在数学函数中。如果数学函数的一个参数值不在函数定义域中,则会将errno设置为EDOM
    
    Macro: int ERANGE
        范围错误,与上面的EDOM恰好相反。EDOM是定义域的话,ERANGER就是值域了。也多用于数学函数中。如果数学函数返回值超过了约定的返回,则会将errno设置为ERANGE
    
    Macro: int EAGAIN
        资源暂时不可获得。这种错误可能是随机的,你再次运行的时候便好了。。。EWOULDBLOCK是EAGAIN的一个别名。

    错误消息:

      我们知道错误代码,但总觉得查文档不方便。幸好库文件给我们提供了错误消息报告函数。这些函数可以报告一个具有说明性的错误消息。部分消息报告函数我们可以自己定义消息格式。

      函数strerror和perror为每一个错误代码都提供了一个标准的错误消息。而变量program_invocation_short_name则可以方便获取程序的名字,告诉我们哪个程序出错。

    几个函数原型:

    #include <string.h>
    char * strerror(int errnum);
    char *strerror_r(int errnum, char *buf, size_t n);

    说明:  strerror和strerror_r两个函数差不多。区别在于安全性,官方文档对strerror的注释是MT-Unsafe race:strerror,而strerror_r则为MT-Safe。strerror返回一个静态申请的字符串缓冲区,该缓冲区被所有线程共享。而strerror_r返回的是一个私有副本,并不被其他线程共享。另外这两个函数都有可能造成内存溢出(静态申请的缓冲区)。尽管strerror_r可以指定字符串长度,但这长度是char *buf的。这函数有两个返回值,一个使用reurn返回,还有一个是char *buf。return返回的依旧是一个静态缓冲区。

    #include<stdio.h>
    void perror(const char *message);

    说明:  perror将error message打印到标准错误输出中。如果你传进的参数是一个空指针,perror会根据errno打印错误消息。如果char *message非空,perror会将message当作错误消息的前缀输出。perror得立即调用,不然errno的值可能发生变化。

    char *program_invocation_name; //等同于argv[0]
    char *program_invocation_short_name //不包含目录名。

    说明:  这两个变量的初始化工作由glibc库在还未调用main函数之前执行。所以在非GNU库中,这两个变量不起效果,在实际代码中我们需要定义_GNU_SOURCE宏,告诉编译器使用GNU库。

      以下两个函数在整个GNU project中使用非常广泛。

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

    说明:  这两个函数的返回和status有关,如果status是0,则正常格式化打印错误消息。全局变量error_message_count也会做自增操作。错误消息的格式如下:program_name: format_string: error_messager_for_errno 。如果status非零,这两个函数将调用exit status,即以状态status退出(不会返回)。关于program_name:全局变量error_print_progname指向的函数决定了program_name的值。error_at_line函数有点特别:多了fname,lineno两个参数。错误消息格式如下:program_name:fname:lineno format_string: error_mesage_for_errno 。如果全局变量error_one_per_line被设置为非零值,每一行只会打印一个错误消息。

      除了以上的错误消息函数,我们还有以下几个:这几个函数主要用在BSD系统中,定义在头文件err.h中,在gnu系统中不推荐使用。

    void warn(const char *format, ...)
    void vwarn(const char *format, va_list ap)
    void warnx(const char *format, ...)
    void vwarnx(const char *format, va_list ap)
    void err(int status, const char *format, ...)
    void verr(int status, const char *format, va_list ap)
    void errx(int status, const char *format, ...)
    void verrx(int status, const char *format, va_list ap)

    各位看官自行查看手册吧。just be a man!!!

    转自:http://www.cnblogs.com/san-fu-su/p/5731000.html

  • 相关阅读:
    Hanoi塔
    采药
    进制转换(大数)
    Load Balancing with NGINX 负载均衡算法
    upstream模块实现反向代理的功能
    epoll
    在nginx启动后,如果我们要操作nginx,要怎么做呢 别增加无谓的上下文切换 异步非阻塞的方式来处理请求 worker的个数为cpu的核数 红黑树
    粘性会话 session affinity sticky session requests from the same client to be passed to the same server in a group of servers
    负载均衡 4层协议 7层协议
    A Secure Cookie Protocol 安全cookie协议 配置服务器Cookie
  • 原文地址:https://www.cnblogs.com/san-fu-su/p/5731000.html
Copyright © 2011-2022 走看看