errno、stderr、perror函数和strerror函数

本文详细介绍了Linux系统中错误处理的基本概念,包括errno错误代码的作用、stderr标准错误输出的应用、perror函数的使用方法以及strerror函数如何将错误代码转换为描述性文本。并通过示例代码展示了这些组件的实际应用。
  1. errno表示错误代码。 记录系统的最后一次错误代码。代码是一个int型的值,在errno.h中定义。系统每一次出错都会对应一个出错代码,例如12表示“Cannot allocate memory"。

  2. stderr是linux(unix)标准出错输出。linux中的一个进程启动时,都会打开三个文件:标准输入、标准输出和标准出错处理。通常这三个文件都与终端联系。这三个文件分别对应文件描述符0、1、2。系队统自定义了三个文件指针stdin、stdout、stderr,分别指向标准输入、标准输出和标准出错输出。通常结合fprintf使用:fprintf(stderr,"error message")。

  3. perror是错误输出函数,在标准输出设备上输出一个错误信息。是对errno的封装。例如perror("fun"),其输出为:fun:后面跟着错误信息(加一个换行符)。包含头文件stdio.h.

  4. stderror是通过参数errno,返回错误信息。即stderror(errno),可用printf函数打印出错信息,用于调试。包含头文件string.h。

测试代码

/*

 *时间:2012.03.11

 *功能:测试errno、perror、strerror和stderr

 *目的:验证linux下出错处理

*/

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>



int main(int argc[],char *argv[])

{
malloc(1);

printf("errno = %d\n",errno);

fprintf(stderr,"stderr\n");

perror("perror");

printf("strerror: %s\n",strerror(errno));



malloc(-1);

printf("errno = %d\n",errno);

fprintf(stderr,"stderr\n");

perror("perror");

printf("strerror: %s\n",strerror(errno));



return 0;

}


运行结果




3、strerror与perror、fprintf(stderr...和printf(stderr....在输出重定向下的差别

3.1    strerror()方法与perror()的用法十分相似。


    先谈谈perror()的用法,这个方法用于将上一条语句(方法)执行后的错误打印到标准输出上。一般情况下(没有使用重定向的话),就是输出到控制台上。 

但是,如果我需要了解另外一个进程的某一个方法执行的错误,或者更briefly,我就希望将错误打印到一个文件里面,perror()就不太合适了! 

为了实现我刚刚说到的要求,我们首先要将错误放到一个字符串里面。这个时候,strerror()就合适了! 

strerror(errno) 

    首先,系统会根据上一条语句的执行错误情况,将errno赋值.。关于这点,我们首先明白两点。第一,errno是一个系统变量,是不需要我们赋值或者声明的。第二,errno是一个int类型的变量,而且其中的值对应一种特定错误类型 

然后,关于streorror()本身,可以这么理解。顾名思义,streorror=string+error,就是将errno值翻译成描述错误类型的string语句!




3.2 fprintf printf

一般情况下,你这两个语句运行的结果是相同的,没有区别,只有一下情况才有区别:

运行你的程序的时候,命令行上把输出结果进行的转向,比如使用下面的命令把你的程序a.c运行的结果转向到记事本文件a.txt:
a.exe > a.txt

在这样的情况,如果使用printf输出错误信息,会保存到a.txt文件里面,如果使用fprintf输出错误,会显示在屏幕上
<think> 我们正在讨论`perror`函数的用法。根据用户的需求,我将结合之前的引用内容,详细解释`perror`函数的工作原理、使用方法注意事项。同时,我会避免涉及其他不相关的内容,确保回答聚焦于`perror`函数。 ### 1. `perror`函数的基本概念 `perror`是C标准库中定义在`<stdio.h>`中的一个函数,用于打印与当前错误代码(存储在全局变量`errno`中)相关联的错误信息。它的函数原型如下: ```c void perror(const char *s); ``` - **参数`s`**:这是一个字符串参数,通常用于提供自定义的错误提示前缀。如果不需要前缀,可以传入`NULL`,但通常我们会传入一个描述性的字符串(如函数名或操作名称)。 - **输出目标**:`perror`总是将错误信息输出到标准错误流(`stderr`),而不是标准输出(`stdout`)[^2][^4]。 ### 2. `perror`的工作流程 当调用`perror`时,它会执行以下步骤: 1. **检查`errno`**:`errno`是一个全局变量,由系统调用或库函数在发生错误时设置。每个错误对应一个唯一的错误代码(如`EACCES`表示权限错误,`ENOENT`表示文件不存在)。 2. **生成错误信息**:`perror`根据`errno`的值,查找对应的标准错误描述字符串(例如,`errno`为`ENOENT`时,描述为“No such file or directory”)。 3. **输出信息**:输出格式为:`s: 错误描述\n`。即先输出传入的字符串`s`,然后输出冒号空格,接着是错误描述,最后是换行符[^2][^4]。 ### 3. 使用示例 以下是一个典型的使用场景(打开文件失败时打印错误): ```c #include <stdio.h> #include <errno.h> // 包含errno的定义 int main() { FILE *file = fopen("nonexistent_file.txt", "r"); if (file == NULL) { perror("fopen failed"); return 1; } // 其他操作... fclose(file); return 0; } ``` - **执行结果**:如果文件不存在,`fopen`返回`NULL`并设置`errno`为`ENOENT`。调用`perror("fopen failed")`会输出: ``` fopen failed: No such file or directory ``` 到标准错误流(通常是控制台)[^2]。 ### 4. 注意事项 - **依赖`errno`**:`perror`的输出完全依赖于当前的`errno`值。因此,必须在出错后立即调用`perror`,避免中间其他操作修改`errno`[^3]。 - **错误描述固定**:`perror`只能输出标准错误描述,无法自定义描述内容。如果需要自定义错误信息,可以结合`strerror`函数: ```c fprintf(stderr, "Custom error: %s\n", strerror(errno)); ``` 这里`strerror(errno)`返回错误描述的字符串,然后通过`fprintf`输出到`stderr`[^3][^4]。 - **输出位置**:`perror`固定输出到`stderr`,而`strerror`只是返回字符串,不负责输出,因此可以灵活控制输出目标[^1][^4]。 ### 5. 与`strerror`的区别 | 特性 | `perror` | `strerror` | |---------------|------------------------------|-----------------------------| | **功能** | 直接输出完整错误信息到`stderr` | 返回错误描述的字符串 | | **输出目标** | 固定为`stderr` | 无输出,需手动调用输出函数 | | **参数** | 接受一个字符串前缀 | 接受错误代码(如`errno`) | | **用法示例** | `perror("Error")` | `printf("%s", strerror(errno))` | ### 6. 完整示例:结合`perror``strerror` ```c #include <stdio.h> #include <errno.h> #include <string.h> int main() { FILE *file = fopen("nonexistent.txt", "r"); if (file == NULL) { // 使用perror输出 perror("perror output"); // 使用strerror输出 fprintf(stderr, "strerror output: %s\n", strerror(errno)); } return 0; } ``` 输出: ``` perror output: No such file or directory strerror output: No such file or directory ``` ### 总结 - **核心作用**:`perror`用于简化错误处理,自动将`errno`转换为可读的错误信息并输出到`stderr`。 - **使用场景**:在系统调用或库函数返回错误后立即调用。 - **注意事项**:避免在调用`perror`前修改`errno`;需要自定义输出格式时改用`strerror`。 §§相关问题§§ 1. `errno`是什么,它是如何被设置的? 2. 在哪些情况下`perror`可能无法正确反映错误? 3. 如何处理多个线程中的`errno``perror`调用? </think> ### `perror`函数用法详解 `perror`是C语言标准库中的错误处理函数,用于输出与**最近一次系统调用错误**相关的可读错误信息。其核心机制是通过全局变量`errno`获取错误代码,并将其转换为人类可读的描述。 #### 一、函数原型基本用法 ```c #include <stdio.h> // 必需头文件 void perror(const char *s); // 函数原型 ``` **参数说明**: - `const char *s`:自定义前缀字符串。会先输出该字符串,再输出系统错误描述。 **典型使用场景**: ```c #include <stdio.h> #include <errno.h> // 包含errno的定义 int main() { FILE *fp = fopen("non_existent.txt", "r"); if (fp == NULL) { // 文件打开失败时 perror("文件打开失败"); // 输出自定义错误前缀 return 1; } // ...其他操作 } ``` **输出示例**: `文件打开失败: No such file or directory` (前半部分为自定义前缀,后半部分是系统错误描述)[^2] --- #### 二、工作原理 1. **依赖`errno`**: - 当系统调用(如`fopen`, `open`, `read`等)失败时,会自动设置全局变量`errno`为特定错误码 - `perror`通过读取`errno`的值获取错误类型 2. **输出流程**: ``` 自定义字符串 + ": " + 系统错误描述 + "\n" ``` 示例调用:`perror("Operation failed")` 可能输出:`Operation failed: Permission denied`[^4] --- #### 三、关键特性 | 特性 | 说明 | |------|------| | **输出位置** | 固定输出到**标准错误流(stderr)**,而非stdout[^1] | | **错误源** | 仅反映**最近一次**系统调用的错误(通过`errno`) | | **描述内容** | 输出标准化的系统错误描述,不可自定义内容[^3] | | **线程安全** | 在多线程环境中需谨慎,因`errno`是全局变量 | --- #### 四、与`strerror`的区别 | 函数 | 输出目标 | 返回值 | 是否自动附加换行 | 典型用法 | |------|----------|--------|------------------|----------| | `perror` | stderr | 无 | 是 | 直接输出完整错误信息 | | `strerror` | 无(需搭配printf) | 错误描述字符串 | 否 | 自定义错误格式 | **示例对比**: ```c // 使用perror perror("Error"); // 直接输出到stderr // 使用strerror fprintf(stderr, "Error: %s\n", strerror(errno)); // 需要手动组装输出 ``` --- #### 五、注意事项 1. **及时性** 必须在系统调用失败后**立即使用**,避免后续操作覆盖`errno`值[^3]: ```c if (write(fd, buf, size) == -1) { perror("写入失败"); // 立即调用 // 不要在此插入其他可能失败的操作 } ``` 2. **错误范围限制** 只能报告标准系统错误(通过`errno`定义),无法捕获: - 应用程序逻辑错误 - 硬件故障(如内存损坏) - 网络超时等非系统错误 3. **多线程环境** 在POSIX系统中,`errno`通常是线程局部变量,但在某些旧系统可能需额外处理线程安全性。 --- ### 典型应用场景 1. **文件操作错误处理** ```c FILE *fp = fopen("/protected/file", "w"); if (!fp) perror("权限拒绝"); ``` 2. **系统调用错误** ```c if (mkdir("/readonly_dir/sub", 0755) == -1) { perror("创建目录失败"); } ``` 3. **网络编程** ```c if (connect(sock, &addr, sizeof(addr)) < 0) { perror("连接服务器失败"); } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值