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一直都保存着上次没调用的返回值,直到下次被调用后值被改变,所以你可以先给它赋值