errno和perror

Linux错误代码及其含义

1.背景说明

(1)errno(error number),Linux系统对各种常见的错误做了个编号,当函数执行错误时,
    函数会返回一个特定的errno编号(int 类型)来告诉我们这个函数哪里错了.
(2)errno是由OS来维护的一个全局变量,任何OS内部函数都可以通过设置errno来告诉上层调
     用者究竟刚才发生了一个什么错误。
(3)Linux系统提供了一个函数perror(print errot),perror函数内部会读取errno并且将这
    个数字转成对应的错误字符串,然后打印出来;

2./usr/include/asm-generic/errno-base.h和errno.h

#define _ASM_GENERIC_ERRNO_BASE_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  /* Argument 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 */    
    
#endif
#ifndef _ASM_GENERIC_ERRNO_H
#define _ASM_GENERIC_ERRNO_H

#include <asm-generic/errno-base.h>

#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 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 */
#define ECANCELED   125 /* Operation Canceled */
#define ENOKEY      126 /* Required key not available */
#define EKEYEXPIRED 127 /* Key has expired */
#define EKEYREVOKED 128 /* Key has been revoked */
#define EKEYREJECTED    129 /* Key was rejected by service */

/* for robust mutexes */
#define EOWNERDEAD  130 /* Owner died */
#define ENOTRECOVERABLE 131 /* State not recoverable */

#define ERFKILL     132 /* Operation not possible due to RF-kill */

#define EHWPOISON   133 /* Memory page has hardware error */

#endif

2.测试代码

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
int bindPort(int nPort)
{
	struct sockaddr_in servaddr;
	int sockfd, ret;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
		return -1;

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(nPort);
	inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr);

	ret = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr));
  if(0!=ret)
  {

    perror("Unable to bind socket");
    cout << "errno = " << errno <<  endl;
    char*errReason = strerror(errno);
    cout << "errReason = " << errReason << endl;
  }
	close(sockfd);
	return ret;
}

bool CheckPortInUse(int nPort)
{
	struct sockaddr_in servaddr;
  bool ifInUse = false;
	int sockfd, ret;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
		return -1;

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(nPort);
	inet_pton(AF_INET, "0.0.0.0", &servaddr.sin_addr);

	ret = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr));
  if(0!=ret && errno == EADDRINUSE)
  {
     ifInUse = true;
  }
	close(sockfd);
	return ifInUse;
}

int main()
{
   //int ret = CheckPortIsAvailable(6379);
   //cout << "ret = " << ret << endl;
   bool ifInUse = CheckPortInUse(6379);
   if(true == ifInUse)
   {
     cout << "端口被占用了" << endl;
   }
   else 
   {
     cout << "端口没有被占用" << endl;
   }
}

<think>我们正在讨论的是在C语言中使用`perror(errno)`的情况。但是请注意,`perror`函数的正确使用方式并不是直接传递`errno`作为参数。让我们详细分析。 首先,回顾`perror`函数的原型: ```c void perror(const char *s); ``` 它接受一个字符串参数`s`,用于在错误消息前打印自定义信息。而`errno`是一个整型变量(通常定义在`errno.h`中),它存储了最近一次系统调用或库函数调用产生的错误代码。 因此,直接使用`perror(errno)`是不正确的,因为`perror`期望一个字符串指针,而`errno`是整数。这样使用会导致类型不匹配,编译器可能会发出警告,并且运行时行为未定义(通常会导致程序崩溃或输出无意义的信息)。 正确的做法是: 1. 在函数调用失败后(通常返回-1或NULL),立即检查`errno`。 2. 使用`perror`并传入一个描述性的字符串(例如文件名或操作名),以便在错误信息中标识错误来源。 例如: ```c FILE *fp = fopen("non_existent_file.txt", "r"); if (fp == NULL) { perror("fopen failed"); // 输出: fopen failed: No such file or directory } ``` 或者,如果你需要获取错误字符串而不直接打印,可以使用`strerror(errno)`,它会返回一个描述错误原因的字符串指针。 现在,针对用户的问题“使用 perror(errno) 的相关说明及注意事项”,我们需要指出: 1. **绝对不要直接将`errno`传递给`perror`**,因为类型不匹配。 2. 正确使用`perror`的方法:传递一个字符串参数,该字符串用于标识错误发生的上下文。 3. 如果确实需要将错误代码作为整数打印,可以使用`printf`打印`errno`的值,同时用`strerror(errno)`获取错误描述。 示例代码: ```c #include <stdio.h> #include <errno.h> #include <string.h> int main() { FILE *fp = fopen("nonexistent.txt", "r"); if (fp == NULL) { // 错误示例:perror(errno); // 这是错误的,会导致崩溃或不可预测行为 // 正确做法1:使用perror perror("Error opening file"); // 正确做法2:使用strerror printf("Error code: %d\n", errno); printf("Error message: %s\n", strerror(errno)); } return 0; } ``` 注意事项: - `perror``strerror`都会使用当前的`errno`值,所以在调用它们之前不要调用其他可能修改`errno`的函数。 - 在多线程环境中,`errno`通常是线程安全的(每个线程有独立的`errno`存储),但具体取决于编译器操作系统。在POSIX系统中,`errno`被定义为线程局部存储。 因此,总结用户的问题:直接使用`perror(errno)`是不正确的,应该传递一个字符串参数。 参考引用[1]中提到了`perror`只能输出标准错误描述,不能自定义错误描述,而`strerror`可以获取错误字符串,这进一步说明了为什么不能直接传递`errno`给`perror`。 现在,根据用户提供的引用[2]中的代码示例,他们正确使用了`perror`:传递一个字符串参数(如`"capture SIGTERM: "`),而不是传递`errno`。所以,用户提供的引用[2]是一个正确用法的示例。 最后,生成相关问题: </think> ### 在C语言中使用 `perror(errno)` 的说明及注意事项 #### 1. **核心问题:`perror(errno)` 的错误使用** **`perror(errno)` 是错误用法**,会导致未定义行为或程序崩溃。原因如下: - `perror()` 函数原型:`void perror(const char *s);` - 它需要**字符串指针**作为参数,但 `errno` 是**整型变量**(定义在 `<errno.h>`) - 直接传递整型 `errno` 会被解释为非法内存地址,导致段错误 #### 2. **正确用法示例** ```c #include <stdio.h> #include <errno.h> int main() { FILE *fp = fopen("nonexistent.txt", "r"); if (fp == NULL) { // 正确做法1:传递描述性字符串 perror("文件打开失败"); // 正确做法2:结合strerror获取错误描述 printf("错误代码 %d: %s\n", errno, strerror(errno)); } return 0; } ``` **输出示例**: ``` 文件打开失败: No such file or directory 错误代码 2: No such file or directory ``` #### 3. `perror` 与 `strerror` 的区别 | 特性 | `perror` | `strerror` | |------|----------|------------| | 参数 | 字符串前缀(如 `"open"`) | 整数错误码(`errno`) | | 输出 | 自动拼接错误描述(`前缀: 描述`) | 仅返回错误字符串 | | 使用场景 | 直接输出完整错误信息 | 需要自定义错误格式时 | | 是否修改 `errno` | 不会修改 | 不会修改 | #### 4. 关键注意事项 1. **参数类型安全** 始终传递字符串指针给 `perror()`,如: ```c perror("read error"); // ✓ 正确 // perror(errno); // ✗ 错误!会导致崩溃 ``` 2. **调用时机** 在错误发生后**立即**调用,避免 `errno` 被后续操作覆盖: ```c int fd = open("file", O_RDONLY); if (fd == -1) { perror("open"); // 立即使用 // 其他操作可能修改 errno } ``` 3. **多线程安全** 在POSIX系统中,`errno` 是线程局部变量(thread-local),可安全用于多线程环境[^2]: ```c // 线程1 if (open("a.txt", O_RDONLY) == -1) { perror("thread1"); // 输出 thread1:... } // 线程2 if (open("b.txt", O_RDONLY) == -1) { perror("thread2"); // 输出 thread2:... } ``` 4. **不可捕获信号的特殊性** 如 `SIGKILL` `SIGSTOP` 不能被捕获(引用[2]示例): ```c if (signal(SIGKILL, handler) == SIG_ERR) { perror("SIGKILL捕获失败"); // 总是输出错误 } ``` #### 5. 错误处理最佳实践 ```c #include <stdio.h> #include <errno.h> #include <string.h> void safe_open(const char *filename) { FILE *fp = fopen(filename, "r"); if (!fp) { // 组合使用两种错误输出 fprintf(stderr, "[%s] 错误 %d: ", filename, errno); perror(""); // 等价于: // fprintf(stderr, "%s: %s\n", filename, strerror(errno)); } } ``` **输出**: ``` [secret.txt] 错误 13: Permission denied ``` #### 6. 常见错误代码对照表 | errno | 宏定义 | 描述 | |-------|--------------|--------------------------| | 2 | `ENOENT` | 文件/目录不存在 | | 5 | `EIO` | 输入输出错误 | | 13 | `EACCES` | 权限不足 | | 22 | `EINVAL` | 无效参数 | | 32 | `EPIPE` | 管道破裂(引用[3]场景) | | 104 | `ECONNRESET` | 连接被对方重置 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值