c语言 errorno

99ANYc3cd6
预计阅读时长 14 分钟
位置: 首页 C语言 正文

errno 是什么?

errno (error number) 是一个在 C 语言标准库中广泛使用的全局整型变量,它的作用是:当一个库函数调用失败时,该函数会将 errno 设置为一个特定的非零整数值,以表示错误的具体类型。

你可以把它想象成一个“错误代码本”,当一个函数(比如打开文件、分配内存等)执行失败时,它不会返回一个有用的结果,而是会往这本“代码本”里记下一个错误编号,你的程序在函数返回后,可以检查这个“代码本”,就知道到底发生了什么问题。


errno 的关键特性

a. 它是一个全局变量

errno 通常被定义为一个宏,展开为一个可以被修改的整数,在大多数实现中,它被声明在头文件 <errno.h> 中。

// 在 <errno.h> 中通常是这样定义的(简化版)
extern int errno; 

extern 关键字表示它是一个外部变量,定义在别处(通常是 C 标准库的实现文件中)。

b. 它的初始值是 0

在程序开始执行时,errno 的初始值通常是 0。0 在 errno 的上下文中代表“没有错误”

c. 成功时,errno 不会被自动重置为 0

这是一个非常重要的点!如果一个函数调用成功了,它不会去修改 errno 的值,这意味着,errno 的值可能来自上一次的调用。在检查 errno 之前,你必须确保你刚刚调用的函数可能失败了

d. 失败时,函数会设置 errno

如果一个库函数报告失败,它负责将 errno 设置为一个非零值,不同的错误对应不同的宏定义。


如何使用 errno

使用 errno 的标准流程如下:

  1. 包含头文件#include <errno.h>
  2. 调用可能失败的函数
  3. 检查函数的返回值:如果返回值表示失败(fopen 返回 NULL),则继续下一步。
  4. 检查 errno 的值:使用 if (errno != 0) 来确认确实发生了错误。
  5. 解释错误:通过 <errno.h> 中定义的宏(如 ENOENT, ENOMEM)来判断具体的错误类型。
  6. 处理错误:打印错误信息、进行清理、退出程序等。
  7. (可选但推荐)重置 errno:在处理完错误后,可以手动将 errno 重置为 0,以避免它影响后续的错误检查。

一个完整的例子:fopen

这个例子展示了如何使用 errno 来处理文件打开失败的情况。

#include <stdio.h>
#include <errno.h>  // 1. 包含 errno.h
#include <string.h> // 用于 strerror()
int main() {
    FILE *fp;
    // 2. 尝试打开一个不存在的文件
    fp = fopen("non_existent_file.txt", "r");
    // 3. 检查返回值
    if (fp == NULL) {
        // 4. 检查 errno 是否被设置
        if (errno != 0) {
            // 5. 解释错误
            printf("错误:无法打开文件 'non_existent_file.txt',\n");
            printf("错误代码 (errno): %d\n", errno);
            // 使用 perror() 或 strerror() 获取可读的错误信息
            // perror() 会自动打印 "错误:无法打开文件..." 然后加上系统错误信息
            perror("perror 输出"); 
            // strerror() 直接返回错误信息的字符串
            printf("strerror 输出: %s\n", strerror(errno));
        }
        return 1; // 返回非零表示程序出错
    }
    // 如果文件成功打开,这里会执行
    printf("文件打开成功!\n");
    fclose(fp);
    return 0;
}

编译并运行这个程序,你会得到类似以下的输出:

错误:无法打开文件 'non_existent_file.txt'。
错误代码 (errno): 2
perror 输出: No such file or directory
strerror 输出: No such file or directory

在这个例子中,fopen 失败并返回 NULL,我们检查到 fpNULL,然后发现 errno 的值是 2。errno.h 中定义了 #define ENOENT 2,这个宏代表 "No such file or directory"(没有那个文件或目录)。perrorstrerror 函数帮助我们将这个数字转换成了人类可读的字符串。


常见的 errno 宏定义

<errno.h> 定义了大量的错误码宏,以下是一些最常见和最重要的:

值 ( 描述
ENOENT 2 No such file or directory (文件或目录不存在)
ENOMEM 12 Out of memory (内存不足)
EINVAL 22 Invalid argument (无效参数)
EAGAIN 11 Resource temporarily unavailable (资源暂时不可用,常用于非阻塞 I/O)
EACCES 13 Permission denied (权限被拒绝)
EBADF 9 Bad file number (坏的文件描述符)
ENOMEM 12 Out of memory (内存不足)
EEXIST 17 File exists (文件已存在,creat 创建一个已存在的文件)

重要注意事项和最佳实践

  1. 检查返回值,再检查 errnoerrno 只在函数报告失败时才有意义,如果一个函数成功,errno 的值是未定义的(可能还是上一次的错误)。

  2. 线程安全:在多线程程序中,errno 是一个全局变量,这会导致严重的竞态条件(Race Condition),如果两个线程同时调用一个可能设置 errno 的函数,一个线程的错误可能会被另一个线程覆盖。

    • 解决方案:现代 C 标准(C11)引入了 errno 的线程安全版本。errno 被定义为一个宏,它指向一个线程局部存储的变量,在支持 C11 的编译器和库中,你通常不需要做任何额外的事情,但在旧环境中,你可能需要使用 errno 的线程安全替代品,或者使用 perror(它本身是线程安全的)。
  3. 不要依赖 errno 的值:只有文档明确说明某个函数会在失败时设置 errno,你才能去检查它,不要随意猜测。

  4. perror() 是你的好朋友perror() 函数会打印你传入的字符串,然后跟着一个冒号和空格,最后是 errno 对应的错误信息(就像上面的例子一样),它比手动 printfstrerror 更方便、更标准。

  5. 重置 errno:在某些复杂的逻辑中,你可能想在处理一个错误后重置它,以防止它干扰后续的错误检查,这很简单:errno = 0;

特性 描述
是什么 一个全局整型变量,用于存储最近一次库函数调用的错误代码。
何时使用 在一个函数调用失败后,通过检查 errno 来确定具体的错误原因。
如何使用 包含 <errno.h> -> 调用函数 -> 检查返回值 -> 检查 errno -> 使用 perror()strerror() 获取信息。
核心原则 成功的函数不会修改 errno;失败的函数会设置 errno
多线程 在旧环境中不安全;在现代 C11 环境中通常是线程安全的。

errno 是 C 语言进行错误处理的基础工具,理解它的正确用法对于编写健壮、可维护的 C 程序至关重要。

-- 展开阅读全文 --
头像
如何提升dede生成静态页面的速度?
« 上一篇 今天
dede微信模板如何适配最新微信版本?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]