linux下错误的捕获:errno和strerror的使用

本文深入探讨了在使用Linux系统API时遇到错误的情况,特别是当调用失败返回-1时如何利用errno全局变量获取失败原因。通过实例代码展示了如何使用strerror()函数进一步翻译错误代码,提供了在实际编程中调试问题的有效策略。
经常在调用linux 系统api 的时候会出现一些错误,比方说使用open() write() creat()之类的函数有些时候会返回-1,也就是调用失败,这个时候往往需要知道失败的原因。这个时候使用errno这个全局变量就相当有用了。
    在程序代码中包含 #include <errno.h>,然后每次程序调用失败的时候,系统会自动用用错误代码填充errno这个全局变量,这样你只需要读errno这个全局变量就可以获得失败原因了。
    例如:
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void)
{
int   fd;
extern int errno;

if((fd = open("/dev/dsp",O_WRONLY)) < 0)
{
   printf("errno=%d\n",errno);
}
  
exit(0);
}
如果dsp设备忙的话errno值将是16。

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
同时也可以使用strerror()来自己翻译
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void)
{
int   fd;
extern int errno;

if((fd = open("/dev/dsp",O_WRONLY)) < 0)
{
   printf("errno=%d\n",errno);
char * mesg = strerror(errno);
   printf("Mesg:%s\n",mesg);
}
  
exit(0);
}
如:dsp设备忙的话将输出如下:
errno=16
Mesg:Device or resource busy
<think>我们正在处理用户关于send函数返回值为6且strerror(errno)为6的错误含义的问题。 根据之前的讨论,我们知道错误号6在POSIX标准中对应ENXIO(No such device or address)。 但是,我们需要确认在send函数的上下文中,这个错误是否可能出现以及其具体含义。 步骤: 1. 回顾send函数的典型行为:send函数通常用于通过套接字发送数据。如果成功,它返回发送的字节数;如果失败,它返回-1,并设置errno以指示错误原因。 2. 用户描述的场景:send函数返回值为6(而不是-1),并且随后调用strerror(errno)得到6对应的错误信息。这里存在一个关键点:当send函数成功发送数据时,它返回发送的字节数(非负整数),此时errno的值通常不会被修改(即保留之前的值)。因此,如果send返回6(表示成功发送了6个字节),那么errno的值可能是之前某个错误留下的,而不是send函数设置的。 然而,用户提到“strerror(errno)也为6”,这意味着在调用send之后,errno的值是6。我们需要考虑两种情况: a) send函数返回6(成功),但errno的值是之前遗留的错误码6(ENXIO)。 b) send函数返回6并不是一个错误,但用户可能误以为这是一个错误情况。 但是,请注意,send函数在成功时返回发送的字节数(>=0),而不会设置errno。只有在返回-1时,errno才被设置为有意义的错误码。 因此,我们推断: - send返回6表示成功发送了6个字节,因此它没有设置errno。 - 此时查看的errno是之前某个函数调用失败设置的,并且没有被清除。 在引用[4]中,我们看到一个send函数的错误处理示例,其中在send返回负数时,检查errno。而在send返回0时,也处理为错误(对端关闭连接)。但是,在send返回正数(如6)时,表示成功,不应该有错误。 所以,用户遇到的问题可能是: 在send返回6(成功)后,立即检查errno,发现errno为6(ENXIO)。这个错误码不是send函数设置的,而是之前的某个函数调用设置的。 结论: - send返回6:表示成功发送6个字节,没有错误。 - errno为6:表示之前有函数调用失败,错误为ENXIO(没有这样的设备或地址)。这个错误可能来自之前的某个系统调用(如打开设备文件、读写设备等)。 建议: 用户应该检查在send之前调用的函数(如open、read、write等)是否有返回错误(-1)的情况,并处理这些错误。同时,在调用可能设置errno的函数后,如果需要检查错误,应该立即检查,而不是在后续成功调用之后检查。 另外,注意errno是一个全局变量,只有在函数返回错误(通常为-1)时才有意义。在成功调用后,errno的值可能保持不变(即保留之前的值),因此不应该在成功调用后直接使用errno来判断错误。 根据引用[1]:errno在函数调用失败时被设置(引用[1]提到当creat、open、write等函数失败返回-1时,系统会用错误代码填充errno)。所以,在成功调用后,errno的值可能是之前的错误。 因此,用户应该: 1. 检查在send之前是否有函数调用失败而没有处理。 2. 在每次函数调用失败(返回-1)时立即处理错误,而不是在后续操作中才检查errno错误号6(ENXIO)的常见原因: - 尝试访问一个不存在的设备文件(如打开一个不存在的设备节点)。 - 在设备操作中指定了超出范围的地址(如lseek到一个无效位置)。 - 在套接字编程中,这个错误不常见,但如果在使用套接字之前操作了某个设备文件,则可能发生。 在套接字编程中,send函数本身不会返回错误号6(ENXIO),因为该错误通常与设备文件I/O相关。因此,这个错误码很可能来自其他操作。 总结回答: - send返回6:成功发送6字节,无错误。 - errno为6:表示之前有操作(非send)发生了ENXIO错误(没有这样的设备或地址),需要检查send之前的代码。 生成相关问题: 1. 如何正确使用errno捕获系统调用错误? 2. 在套接字编程中,send函数可能返回哪些错误?如何正确处理? 3. 如何避免errno的误用(如在成功调用后检查errno)? 4. 错误号6(ENXIO)通常发生在哪些系统调用中?</think>根据您的查询提供的引用内容,当`send()`函数返回值为6且`strerror(errno)`也显示错误号6时,这表示以下含义: ### 错误解析 1. **`send()`返回值6的含义**: - `send()`函数返回**正整数(如6)表示成功发送的字节数**,而不是错误(引用[4][5])。 - 在您的场景中,`send()`返回6表明它已成功发送了6字节的数据到目标套接字,**这不是错误状态**。 2. **`strerror(6)`的含义**: - 错误号6对应POSIX标准的`ENXIO`(**No such device or address**),即“没有这样的设备或地址”(引用[1][2])。 - 该错误通常由以下操作触发: - 尝试访问不存在的设备文件(如`/dev/xxx`) - 操作已断开连接的硬件设备 - 无效的I/O地址访问(如设备未初始化) ### 矛盾原因分析 - **关键矛盾**: `send()`返回6(成功)但`errno`为6(错误),表明**`errno`的值并非由本次`send()`调用设置**,而是由**之前的某个系统调用遗留**的错误状态(引用[1][2])。 - **典型场景**: 在调用`send()`之前,可能存在以下失败操作: ```c int fd = open("/dev/invalid_device", O_RDWR); // 此操作失败,设置errno=6 // ...未检查错误直接继续执行... send(socket_fd, buffer, len, 0); // 成功发送6字节,但未清除之前的errno ``` ### 解决方案 1. **检查`send()`之前的操作**: 重点排查`open()`、`ioctl()`、`write()`等可能操作设备的函数调用,例如: ```c int device_fd = open("/dev/sensor", O_RDONLY); if (device_fd == -1) { // 立即处理错误:打印errno并退出 perror("open failed"); exit(1); } ``` 2. **正确使用错误处理模式**: - 每次系统调用后**立即检查返回值**(引用[4]) - 仅在返回`-1`时读取`errno`(成功调用会保留之前的`errno`值) ```c if (send(sock, buf, len, 0) == -1) { // 此时errno有效 printf("Send error: %s\n", strerror(errno)); } else { // 发送成功,忽略当前errno值 } ``` ### 错误号6(ENXIO)常见触发场景 | 操作类型 | 示例 | 原因 | |-------------------|-------------------------------|--------------------------| | 设备文件访问 | `open("/dev/missing", O_RDWR)` | 设备文件不存在或未加载驱动 | | 硬件控制 | `ioctl(fd, INVALID_CMD)` | 设备不支持该命令 | | 套接字配置 | `setsockopt()` 使用无效参数 | 底层驱动返回设备错误 | > 在套接字编程中,`send()`**本身不会触发ENXIO错误**(引用[3][4])。该错误通常源于底层设备访问问题,而非网络协议栈。 ### 相关问题 1. 如何避免`errno`在连续系统调用中的误用? 2. `send()`函数在哪些情况下会返回`EPIPE`(错误号32)错误? 3. Linux设备驱动开发中如何处理`ENXIO`错误? 4. 如何编写健壮的错误处理代码来防止未清除的`errno`干扰? [^1]: errno用于Linux下的错误捕获,在运行creat(),open(),write()之类的函数时有些时候会调用失败返回-1,这时候若在程序中include<errno.h>这个头文件,每次发生错误时,系统会自动用错误代码填充errno这个全局变量。 [^2]: 当linuc C api函数发生异常时,一般会将errno变量赋一个整数值,不同的值表示不同的含义,可以通过查看该值推测出错的原因。 [^3]: 此时send、recv或write函数将返回-1,errno为EPIPE,可视情况关闭socket或其他处理。 [^4]: send函数返回值错误处理。如果返回-1且errno为EINTR/EAGAIN,通常需要重试。 [^5]: send()函数在成功时返回发送的字节数(非负数),失败时返回-1。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值