errno是什么?

来源:互联网 发布:lol物品数据库s7 编辑:程序博客网 时间:2024/06/05 08:24

 

1.为防止和正常的返回值混淆,系统调用并不直接返回错误码,而是将错误码放入一个名为errno的全局变量中。如果一个系统调用失败,你可以读出errno的值来确定问题所在。

errno不同数值所代表的错误消息定义在errno.h中,你也可以通过命令"man 3 errno"来察看它们。

需要注意的是,errno的值只在函数发生错误时设置,如果函数不发生错误,errno的值就无定义,并不会被置为0。另外,在处理errno前最好先把它的值存入另一个变量,因为在错误处理过程中,即使像printf()这样的函数出错时也会改变errno的值。

2.简单的说,errno在标准C中是一个整型变量,在errno.h中声明,C标准库中实现。多线程技术中,为了使errno线程安全,使用宏定义替代了简单的extern   int   errno声明。man   errno,   再看看C99标准文档,就明白了。  
   
  ---选自/usr/include/bits/errno.h------  
  //当使用多线程时,errno是个宏定义  
  #     if   !defined   _LIBC   ||   defined   _LIBC_REENTRANT  
  /*   When   using   threads,   errno   is   a   per-thread   value.     */  
  #       define   errno   (*__errno_location   ())  
  #     endif  
  #   endif   /*   !__ASSEMBLER__   */  
  #endif   /*   _ERRNO_H   */  
   
  ----选择/usr/include/errno.h-------  
  //标准的errno定义,在errno.h中声明,libc标准库中实现定义。  
  /*   Declare   the   `errno'   variable,   unless   it's   defined   as   a   macro   by  
        bits/errno.h.     This   is   the   case   in   GNU,   where   it   is   a   per-thread  
        variable.     This   redeclaration   using   the   macro   still   works,   but   it  
        will   be   a   function   declaration   without   a   prototype   and   may   trigger  
        a   -Wstrict-prototypes   warning.     */  
  #ifndef   errno  
  extern   int   errno;  
  #endif  

3.
gcc不同的版本定义不一样的,是一个易失变量  
你#include   <errno.h>就可以了不要再自己extern   int   errno;  
 
【总结:】 errno只需要你包含它的头文件即可,不用在程序中定义它。
********************************


errno是libc的全局变量,内核并不会直接访问它。
系统调用返回时,把错误结果放在寄存器%eax中,
libc会把这个%eax复制给errno,然后返回-1给调用的程序。
这样,程序得到的系统调用的结果是-1,具体的错误在errno中。

********************************
查看错误代码errno是调试程序的一个重要方法。当C api函数发生异常时,一般会将errno变量(需include errno.h)赋一个整数值,不同的值表示不同的含义,可以通过查看该值推测出错的原因。

在/usr/include/asm/errno.h 中有对应错误码的定义。


使用TLS
多线程运行库
首先,errno必须成为各个线程的私有成员。在glibc中,errno被定义为一个宏,如下:

#define errno (*__errno_location ())

函数__errno_location在不同的库版本下有不同的定义,在单线程版本中,它仅直接返回了全局变量errno的地址。而在多线程版本中,不同线程调用__errno_location返回的地址则各不相同。在MSVC中,errno同样是一个宏,其实现方式和glibc类似。

 

errno实际上,并不是我们通常认为的是个整型数值,而是通过整型指针来获取值的。这个整型就是线程安全的。

另外,宏之所以这样实现,是因为标准库规定了必须能够通过&errno方式取得保存错误代码的变量的地址,因此 __errno_location()函数的返回值是指针,并把宏定义为解引用函数返回的地址*__errno_location()。如果 __errno_location直接返回int类型,此时就无法取得保存错误代码的变量的地址。


************************************
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(void)
{
 int  fd;
 errno = 0;

 if((fd = open("no/such/file",0)) < 0)
 {
  printf("errno=%d/n",errno);
  char * mesg = strerror(errno);
  printf("Mesg:%s/n",mesg); 
 }
【注意】在errno的错误返回值中没有0的定义项,并且errno一直都保存着上次没调用的返回值,直到下次被调用后值被改变,所以你可以先给它赋值