【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 的码。

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

相关推荐
誰能久伴不乏2 小时前
【Qt实战】工业级多线程串口通信:从底层协议设计到完美收发闭环
linux·c++·qt
2401_832131952 小时前
模板错误消息优化
开发语言·c++·算法
金枪不摆鳍2 小时前
算法--二叉搜索树
数据结构·c++·算法
liu****2 小时前
4.Qt窗口开发全解析:菜单栏、工具栏、状态栏及对话框实战
数据库·c++·qt·系统架构
近津薪荼2 小时前
优选算法——双指针6(单调性)
c++·学习·算法
helloworldandy3 小时前
高性能图像处理库
开发语言·c++·算法
2401_836563183 小时前
C++中的枚举类高级用法
开发语言·c++·算法
代码无bug抓狂人3 小时前
动态规划(附带入门例题)
c语言·算法·动态规划
EmbedLinX3 小时前
C++ 面向对象
开发语言·c++