【C/C++】strerror、GetLastError 和 errno 的含义和区别?

strerrorGetLastErrorerrno 是 C/C++ 编程中用于错误检测与报告的三个重要机制,但它们来自不同的标准或平台,用途和使用方式有明显区别。下面详细解释它们的含义、来源、用法及差异:


1. errno(错误号变量)

含义:

  • errno 是一个 全局整型变量 (在多线程环境中通常是线程局部存储),用于记录 C 标准库函数执行过程中发生的错误代码。
  • 它定义在 <errno.h>(C)或 <cerrno>(C++)中。

特点:

  • 初始值为 0(表示无错误)。
  • 当某些标准库函数(如 fopen, malloc, strtol 等)失败时,会将特定的错误码(如 ENOENT, ENOMEM)写入 errno
  • 不会自动清零 :成功调用不保证 errno 被重置为 0,因此应在出错后立即检查。
  • 错误码是 POSIX/ANSI C 标准定义的,具有跨平台性(但具体值可能因系统而异)。

示例:

c 复制代码
#include <stdio.h>
#include <errno.h>
#include <string.h>

FILE* fp = fopen("nonexistent.txt", "r");
if (!fp) {
    printf("Error code: %d\n", errno);
    printf("Error message: %s\n", strerror(errno));
}

2. strerror

含义:

  • 函数 char* strerror(int errnum)errno 类型的错误码转换为 人类可读的错误字符串
  • 定义在 <string.h>(C)或 <cstring>(C++)中。

作用:

  • errno 的数值(如 2)转为字符串(如 "No such file or directory")。
  • 通常与 errno 配合使用。

示例:

c 复制代码
printf("Error: %s\n", strerror(errno));

⚠️ 注意:strerror 不是线程安全的(返回静态缓冲区指针)。可使用 strerror_r(POSIX)或 strerror_s(C11/MSVC)替代以获得线程安全版本。


3. GetLastError(Windows 特有)

含义:

  • Windows API 提供的函数,用于获取 最近一次调用 Windows API 函数 失败时的错误代码。
  • 定义在 <windows.h> 中。
  • 返回类型为 DWORD(32 位无符号整数)。

特点:

  • 仅适用于 Windows 平台
  • 只对 Windows API 函数 (如 CreateFile, RegOpenKey, WSAStartup 等)有效,不适用于 C 标准库函数
  • 每个线程有自己的"最后错误"值(线程局部)。
  • 成功调用某些 API 可能会重置错误码为 0,但并非所有函数都如此,因此应立即在失败后调用 GetLastError

获取错误信息:

需配合 FormatMessage 将错误码转为字符串:

c 复制代码
#include <windows.h>
#include <stdio.h>

HANDLE hFile = CreateFile("nonexistent.txt", ...);
if (hFile == INVALID_HANDLE_VALUE) {
    DWORD err = GetLastError();
    LPSTR msg;
    FormatMessageA(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPSTR)&msg, 0, NULL
    );
    printf("Windows error: %lu - %s", err, msg);
    LocalFree(msg);
}

三者的核心区别总结:

项目 errno strerror GetLastError
来源 C 标准库 / POSIX C 标准库 Windows API
平台 跨平台 跨平台 仅 Windows
适用函数 C 标准库函数(如 fopen, malloc 配合 errno 使用 Windows API 函数(如 CreateFile
类型 全局变量(int) 函数(转错误码为字符串) 函数(返回 DWORD 错误码)
线程安全 通常是线程局部(现代实现) 通常不安全 (用 strerror_r/s 替代) 线程局部(安全)
典型错误码 ENOENT (=2), EINVAL (=22) --- ERROR_FILE_NOT_FOUND (=2), ERROR_ACCESS_DENIED (=5)

常见误区:

  • ❌ 用 GetLastError() 检查 fopen() 失败原因 → 错误! 应用 errno
  • ❌ 用 errno 检查 CreateFile() 失败原因 → 错误! 应用 GetLastError()
  • ✅ 正确做法:根据调用的函数类型选择对应的错误机制。

补充:C++ 中的异常 vs 这些机制

  • C++ 标准库(如 std::fstream)通常不设置 errno ,而是通过状态标志(如 fail())或抛出异常(如果启用了异常)。
  • Windows C++ 程序若混合使用 CRT 和 WinAPI,需同时处理 errnoGetLastError

总结口诀:

标准库看 errno,WinAPI 查 GetLastError
strerrorerrno 变文字,
FormatMessageGetLastError 的码。

合理区分使用场景,才能准确诊断程序错误。

相关推荐
leo_messi9411 分钟前
多线程(五) -- 并发工具(二) -- J.U.C并发包(八) -- CompletableFuture组合式异步编程
android·java·c语言
jie1889457586619 分钟前
c语言------
c语言·开发语言
是娇娇公主~2 小时前
Lambda表达式详解
数据结构·c++
leaves falling2 小时前
C++ string 类:从入门到模拟实现
开发语言·c++
样例过了就是过了3 小时前
LeetCode热题100 柱状图中最大的矩形
数据结构·c++·算法·leetcode
liuyao_xianhui3 小时前
优选算法_最小基因变化_bfs_C++
java·开发语言·数据结构·c++·算法·哈希算法·宽度优先
AI+程序员在路上4 小时前
Linux C 条件变量阻塞线程用法:等待时CPU占用率为0
linux·运维·c语言
jimy14 小时前
C语言实现-----面向对象编程
c语言·数据结构
cch89184 小时前
易语言与C++:编程语言终极对决
开发语言·c++
不爱吃糖的程序媛4 小时前
鸿蒙PC tiny-AES-c三方库适配实践
c语言·华为·harmonyos