open()失败后应立即检查errno:返回-1时errno有效,需在系统调用后立刻读取;跨平台应使用EACCES等宏而非数字;Windows用strerror_s()须传缓冲区大小,Linux用strerror_r();std::filesystem操作失败仍依赖底层errno。

open() 失败后怎么拿到具体错误码
直接看 errno。C++ 里调用系统级文件操作(比如 open()、fopen())失败时,errno 会被自动设置为对应错误编号,但它不会清零——所以必须在判断返回值失败**之后立刻读取**,否则后续任意系统调用都可能覆盖它。
-
open()返回 -1 表示失败,此时errno才有效;fopen()返回nullptr同理 - 别在 if 判断里嵌套多个系统调用,比如
if (open(...) == -1 && printf("err: %d", errno))——printf本身可能改写errno - Windows 下用
_open()也遵循同一规则,但要注意 CRT 版本兼容性(VS2015+ 默认启用安全增强,部分老写法会报错)
strerror_s() 安全拼字符串的硬要求
strerror_s() 是 Windows 上推荐的线程安全版本,但它的参数顺序和行为和 POSIX 的 strerror() 完全不同:它不返回指针,而是把字符串写进你提供的缓冲区,并且**必须指定缓冲区大小**。
- 典型误写:
char buf[256]; strerror_s(buf, errno);—— 缺少长度参数,编译不过(VS 会报 C4996 或 C2660) - 正确写法:
char buf[256]; strerror_s(buf, sizeof(buf), errno); - Linux/macOS 没有
strerror_s(),得用strerror_r()(注意:glibc 和 musl 实现不兼容,返回值语义不同) - 缓冲区太小会导致截断,但函数仍返回 0(成功),不会报错;建议至少留 256 字节
跨平台查错别硬背 errno 值
errno 数值本身没意义,不同系统相同数字代表不同错误。真正要关注的是宏名,比如 EACCES、ENOENT、EMFILE —— 这些才是可移植的判断依据。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 检查权限问题?直接比
errno == EACCES,而不是errno == 13 - 文件不存在?用
errno == ENOENT,不是2 - 打开太多文件?
EMFILE(进程级)和ENFILE(系统级)要区分,尤其在容器或 ulimit 限制环境下 - 宏定义在
<cerrno>(C++)或<errno.h>(C)里,不用额外 include 其他头文件
std::filesystem::open_file() 不抛异常,照样要查 errno
C++17 的 std::filesystem 并不封装底层错误细节,比如 std::filesystem::ifstream 构造失败,或者 std::filesystem::create_directories() 返回 false,背后仍是系统调用 + errno。它只是把错误“吞掉”了,没给你暴露出来。
立即学习“C++免费学习笔记(深入)”;
- 想定位问题,得退回到 C 层:用
open()或_open()手动试,再读errno -
std::filesystem::status()可能因权限不足返回std::filesystem::file_status()空值,此时errno才是唯一线索 - 某些 libc++ 实现(如 macOS)在
std::filesystem内部会重置errno,所以不能依赖它在高阶 API 调用后还有效
最常被忽略的一点:errno 是线程局部的,但如果你在信号处理函数里访问它,或者用了 fork() 后父子进程共享状态,结果就不可靠。实战中优先用返回值+宏判断,而不是打印数字再查表。


















