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

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

相关推荐
小欣加油1 分钟前
Leetcode2058 找出临界点之间的最小和最大距离
数据结构·c++·算法·leetcode·职场和发展
Patrick在香港5 分钟前
Python 拉取 C&SD 官方 API:香港 2022 年已跨过“超老龄线“,而抚养比正在爬回 1961
android·c语言·python·数据分析·时序数据库·数据可视化·香港
王老师青少年编程18 分钟前
2026年山东省小学组【信息学体验营】复赛真题及题解T2:小兔子爬楼梯
c++·真题·山东省·csp·信奥赛·复赛·信息学体验营
Yfhonier21 分钟前
6441. 特别的除法
c++·算法
OPEN-F34 分钟前
C++17新特性精讲:结构化绑定、if constexpr与实用类型
开发语言·c++
OPEN-F38 分钟前
C++并发编程:线程与互斥锁
开发语言·c++
码匠许师傅40 分钟前
【设计模式精讲】11.桥接模式(Bridge)
c++·设计模式·桥接模式·uml
小小、码农1 小时前
【网络】套接字(Socket)编程——TCP版
linux·服务器·网络·c++·网络协议·tcp/ip
天空之城--1 小时前
C++ ODR-use 深度解析:从原理到实战
c++
旖旎夜光1 小时前
LeetCode 974:和可被 K 整除的子数组(前缀和) —— 题解
数据结构·c++·算法·leetcode·前缀和