errno

一个简单的测试小程序:

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <error.h>

main()

{

extern int errno;

char *path = "/root/tmp11";

if (rmdir(path) == 0)

{

fprintf(stderr, "deleted the directory %s.\n", path);

}

else

{

fprintf(stderr, "cant't delete the directory %s.\n", path);

fprintf(stderr, "errno: %d\n", errno);

fprintf(stderr, "ERR: %s\n", strerror(errno));

}

}

其中errno的使用了解不深,于是查了一下:


一、errno的由来 

在C编程中,errno是个不可缺少的变量,特别是在网络编程中。如果你没有用过errno,那只能说明你的程序不够健壮。当然,如果你是WIN32平台的GetLastError(),效果也是一样的。 

为什么会使用errno呢?个人认为,这是系统库设计中的一个无奈之举,他更多的是个技巧,而不是架构上的需要。我们观察下函数结构,可以发现,函数的参数返回值只有一个,这个返回值一般可以携带错误信息,比如负数表示错误,而正数表述正确的返回值,比如recv函数。但是对于一些返回指针的函数,如:char *get_str();这个方法显然没有用的。NULL可以表示发生错误,但是发生什么错误却毫无办法。于是,errno就诞生了。全局变量errno可以存放错误原因,当错误发生时,函数的返回值是可以通过非法值来提示错误的发生。 


二、errno的线程安全 

errno是全局变量,但是在多线程环境下,就会变得很恐怖。当你调用一个函数时,发现这个函数发生了错误,但当你使用错误原因时,他却变成了另外一个线程的错误提示。想想就会觉得是件可怕的事情。

将errno设置为线程局部变量是个不错的主意,事实上,GCC中就是这么干的。他保证了线程之间的错误原因不会互相串改,当你在一个线程中串行执行一系列过程,那么得到的errno仍然是正确的。 

看下,bits/errno.h的定义:

 # ifndef __ASSEMBLER__

 /* Function to get address of global `errno' variable. */ 

extern int *__errno_location (void) __THROW __attribute__ ((__const__)); 

# if !defined _LIBC || defined _LIBC_REENTRANT 

/* When using threads, errno is a per-thread value. */ 

# define errno (*__errno_location ()) 

# endif 

# endif /* !__ASSEMBLER__ */ 

而errno.h中是这样定义的: 

/* 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 

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


三、errno的实现 

static pthread_key_t key; 

static pthread_once_t key_once = PTHREAD_ONCE_INIT; 

static void make_key() 

(void) pthread_key_create(&key, NULL); 

int *_errno() 

int *ptr ; 

(void) pthread_once(&key_once, make_key); 

if ((ptr = pthread_getspecific(key)) == NULL)

ptr = malloc(sizeof(int)); 

(void) pthread_setspecific(key, ptr); 

return ptr ;


四、errno的应用 

errno在库中得到广泛的应用,但是,错误编码实际上不止那么多。我们需要在自己的系统中增加更多的错误编码。一种方式就是直接利用errno,另外一种方式就是定义自己的user_errno。 

使用user_errno,strerror可能无法解析,这需要自己解决。但errno使用线程变量的方式值得借鉴。

errno .h errno.h- - 查看错误代码errno是调试程序的一个重要方法。当linuc C api函数发生异常时,一般会将errno变量(需include errno.h)赋一个整数值,不同的值表示不同的含义,可以通过查看该值推测出错的原因。在实际编程中用这一招解决了不少原本看来莫名其妙的问题。比较麻烦的是每次都要去linux源代码里面查找错误代码的含义,现在把它贴出来,以后需要查时就来这里看了。 

以下来自linux 2.4.20-18的内核代码中的/usr/include/asm/errno.h 

#ifndef _I386_ERRNO_H 

#define _I386_ERRNO_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 /* Arg 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 */ 

#define EDEADLK 35 /* Resource deadlock would occur */ 

#define ENAMETOOLONG 36 /* File name too long */ 

#define ENOLCK 37 /* No record locks available */ 

#define ENOSYS 38 /* Function not implemented */ 

#define ENOTEMPTY 39 /* Directory not empty */ 

#define ELOOP 40 /* Too many symbolic links encountered */ 

#define EWOULDBLOCK EAGAIN /* Operation would block */ 

#define ENOMSG 42 /* No message of desired type */ 

#define EIDRM 43 /* Identifier removed */ 

#define ECHRNG 44 /* Channel number out of range */ 

#define EL2NSYNC 45 /* Level 2 not synchronized */ 

#define EL3HLT 46 /* Level 3 halted */

#define EL3RST 47 /* Level 3 reset */ 

#define ELNRNG 48 /* Link number out of range */

#define EUNATCH 49 /* Protocol driver not attached */ 

#define ENOCSI 50 /* No CSI structure available */ 

#define EL2HLT 51 /* Level 2 halted */ 

#define EBADE 52 /* Invalid exchange */ 

#define EBADR 53 /* Invalid request descriptor */ 

#define EXFULL 54 /* Exchange full */ 

#define ENOANO 55 /* No anode */ 

#define EBADRQC 56 /* Invalid request code */ 

#define EBADSLT 57 /* Invalid slot */ 

#define EDEADLOCK EDEADLK 

#define EBFONT 59 /* Bad font file format */ 

#define ENOSTR 60 /* Device not a stream */ 

#define ENODATA 61 /* No data available */ 

#define ETIME 62 /* Timer expired */ 

#define ENOSR 63 /* Out of streams resources */ 

#define ENONET 64 /* Machine is not on the network */ 

#define ENOPKG 65 /* Package not installed */ 

#define EREMOTE 66 /* Object is remote */ 

#define ENOLINK 67 /* Link has been severed */ 

#define EADV 68 /* Advertise error */ 

#define ESRMNT 69 /* Srmount error */ 

#define ECOMM 70 /* Communication error on send */ 

#define EPROTO 71 /* Protocol error */ 

#define EMULTIHOP 72 /* Multihop attempted */ 

#define EDOTDOT 73 /* RFS specific error */ 

#define EBADMSG 74 /* Not a data message */ 

#define EOVERFLOW 75 /* Value too large for defined data type */ 

#define ENOTUNIQ 76 /* Name not unique on network */ 

#define EBADFD 77 /* File descriptor in bad state */ 

#define EREMCHG 78 /* Remote address changed */ 

#define ELIBACC 79 /* Can not access a needed shared library */ 

#define ELIBBAD 80 /* Accessing a corrupted shared library */ 

#define ELIBSCN 81 /* .lib section in a.out corrupted */ 

#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ 

#define ELIBEXEC 83 /* Cannot exec a shared library directly */ 

#define EILSEQ 84 /* Illegal byte sequence */ 

#define ERESTART 85 /* Interrupted system call should be restarted */ 

#define ESTRPIPE 86 /* Streams pipe error */ 

#define EUSERS 87 /* Too many users */ 

#define ENOTSOCK 88 /* Socket operation on non-socket */ 

#define EDESTADDRREQ 89 /* Destination address required */ 

#define EMSGSIZE 90 /* Message too long */ 

#define EPROTOTYPE 91 /* Protocol wrong type for socket */ 

#define ENOPROTOOPT 92 /* Protocol not available */

#define EPROTONOSUPPORT 93 /* Protocol not supported */ 

#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ 

#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ 

#define EPFNOSUPPORT 96 /* Protocol family not supported */ 

#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ 

#define EADDRINUSE 98 /* Address already in use */ 

#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ 

#define ENETDOWN 100 /* Network is down */ 

#define ENETUNREACH 101 /* Network is unreachable */ 

#define ENETRESET 102 /* Network dropped connection because of reset */ 

#define ECONNABORTED 103 /* Software caused connection abort */ 

#define ECONNRESET 104 /* Connection reset by peer */ 

#define ENOBUFS 105 /* No buffer space available */ 

#define EISCONN 106 /* Transport endpoint is already connected */ 

#define ENOTCONN 107 /* Transport endpoint is not connected */ 

#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ 

#define ETOOMANYREFS 109 /* Too many references: cannot splice */ 

#define ETIMEDOUT 110 /* Connection timed out */ 

#define ECONNREFUSED 111 /* Connection refused */ 

#define EHOSTDOWN 112 /* Host is down */ 

#define EHOSTUNREACH 113 /* No route to host */ 

#define EALREADY 114 /* Operation already in progress */ 

#define EINPROGRESS 115 /* Operation now in progress */ 

#define ESTALE 116 /* Stale NFS file handle */ 

#define EUCLEAN 117 /* Structure needs cleaning */ 

#define ENOTNAM 118 /* Not a XENIX named type file */ 

#define ENAVAIL 119 /* No XENIX semaphores available */ 

#define EISNAM 120 /* Is a named type file */ 

#define EREMOTEIO 121 /* Remote I/O error */ 

#define EDQUOT 122 /* Quota exceeded */ 

#define ENOMEDIUM 123 /* No medium found */ 

#define EMEDIUMTYPE 124 /* Wrong medium type */ 

#endif

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值