跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

c++如何在C和C++文件流之间转换_fileno获取文件描述符【附源码】

不行,_fileno不是标准C++函数,仅MSVC/MinGW等部分环境支持,且需流已打开、绑定真实文件、使用binary模式,并先获取FILE(但C++标准不暴露FILE),跨平台不可靠。 用
_fileno
从 C++
std::fstream
拿到 C 文件描述符,行不行? 行,但必须确保流底层绑定的是真实文件(非内存、管道、重定向等),且已打开、未缓冲失败。
_fileno
是 MSVC 和部分 POSIX 兼容环境(如 MinGW)提供的扩展函数, 不是标准 C++ ,GCC/Clang 在纯 Linux 下默认不提供,会报
undefined reference to `_fileno'
。 常见错误现象:
std::ofstream f("out.txt"); int fd = _fileno(f); // fd == -1 或崩溃
—— 因为
f
内部 FILE* 可能未初始化或已被关闭。 只对
std::fstream
/
std::ifstream
/
std::ofstream
有效,且必须用
std::ios_base::binary
模式打开(文本模式下换行处理可能干扰底层 fd 一致性) 调用前务必检查流状态:
if (f.is_open() && f.rdbuf() != nullptr)
MSVC 中需包含
;MinGW 需链接
-lmsvcrt
或启用
-D__USE_MINGW_ANSI_STDIO
C++ 流怎么拿到对应的
FILE*
?这是
_fileno
的前提
_fileno
输入是
FILE*
,不是 C++ 流对象。C++ 标准库不暴露
FILE*
,但各实现有私有接口:MSVC 提供
_get_stream_handle()
(仅 debug 版可用),lib c++ 和 libstdc++ 均不公开该能力。所以「先取
FILE*
再调
_fileno
」这条路在跨平台项目里基本走不通。 实际能稳定用的路径只有一条:绕过 C++ 流,用 C 打开文件,再用
fdopen
构造 C++ 流 —— 反向操作更可靠。 立即学习 “ C++免费学习笔记(深入) ”; C知道 CSDN推出的一款AI技术问答工具 下载 正确姿势:
int fd = open("data.bin", O_RDWR | O_CREAT, 0644); std::filebuf fb; fb.attach(fd); std::iostream fs(&fb);
不要试图从
std::cout
、
std::cin
或重定向后的流取 fd —— 它们的
FILE*
可能被封装、复用或根本不存在(如 libc++ 用自研 buffer)
std::filebuf::fd()
是 GNU libstdc++ 的扩展(非标准),返回 int,但仅当用
attach()
绑定过 fd 后才有效;直接构造的流返回 -1 Linux/macOS 下替代
_fileno
的可移植方案 别硬啃
_fileno
。POSIX 系统上,所有 I/O 最终都落到 fd,关键是怎么让 C++ 流和 fd 对齐。标准做法是:用
open()
/
socket()
等系统调用拿到 fd,再用
fdopen()
包装成
FILE*
,最后用
std::filebuf
的非标准构造函数(libstdc++ 支持)或自己继承
std::streambuf
转接。 示例(libstdc++ 环境):
int fd = open("log.txt", O_WRONLY | O_APPEND | O_CREAT, 0644); FILE* fp = fdopen(fd, "a"); std::filebuf fb; fb.pubsetbuf(nullptr, 0); fb.open("/dev/null", std::ios_base::out); // 占位 // 实际需反射调用 _M_file设为fp(不推荐)→ 更稳妥:直接用 fp + fprintf
真正跨平台的做法是:放弃混合使用,同一模块统一用 C 文件 I/O(
fread
/
fwrite
)或统一用 C++ 流(
read
/
write
),中间不转换 若必须桥接(如调第三方 C 库需要 fd),优先用
dup(fd)
复制一份,避免 C++ 流析构时误关原始 fd 注意缓冲区同步:
fflush(fp)
和
fs.flush()
不互通,混用极易丢数据 为什么你看到的「附源码」示例总在 Windows 上跑通? 因为 MSVC 的
std::filebuf
内部确实持有一个
FILE*
,且
_fileno
就是直接读那个字段 —— 这属于实现细节泄漏。换个编译器、升个 libc++ 版本、甚至加个
-O2
,就可能因内联优化导致
rdbuf()
返回空指针。 测试时别只看是否编译通过,要验证 fd 是否真能
read()
/
write()
—— 很多“成功”只是返回了某个无效值(如 3,其实是 stderr 的 fd) CI 环境(尤其是 Linux + Clang)大概率挂掉,别信本地 Windows 测试结果 最隐蔽的坑:
std::ofstream f("x.txt", std::ios::app); int fd = _fileno(f.rdbuf()->_IO_file_flags ? ...)
—— 这种野指针访问在 ASan 下立刻崩溃 真要拿 fd,就老实用
open()
;真要用 C++ 流,就别动它的底层。两者硬凑,边界模糊的地方比代码还多。

相关文章