fread和fwrite在C++中可直接使用,因C++标准库兼容C标准库,需显式包含;二者与C++流性能无显著差异,但语义、错误处理及跨平台序列化需谨慎。

为什么 fread 和 fwrite 在 C++ 里能直接用
因为 C++ 标准库明确兼容 C 标准库头文件,(或旧式 )里的 fread、fwrite、FILE* 全都合法可用——它们不是“C 风格的替代品”,而是 C++ 语言本身支持的底层 I/O 接口。
常见错误现象:error: 'fread' was not declared in this scope,通常是因为没加 #include ,或者误用了 后以为自动带了 C IO 函数。
- 必须显式包含
#include;用也可,但推荐前者 -
FILE*指针不能和std::ifstream/std::ofstream混用,二者底层缓冲、打开模式、异常行为完全不兼容 - Windows 下若用
"wb"模式写二进制,别漏掉b,否则换行符可能被悄悄转义
fread/fwrite 和 std::ifstream::read/std::ofstream::write 性能差多少
在绝大多数场景下,**没明显差别**。两者底层通常共享同一套 libc 缓冲机制(如 glibc 的 _IO_FILE),std::ifstream 默认也开启缓冲,且会把 read() 转发给 fread 级别调用。
真正影响性能的是:缓冲区大小、是否禁用同步、数据块粒度。
- 默认情况下,
std::ios_base::sync_with_stdio(true)(这是 C++ 流默认状态),此时std::cin/cout和stdin/stdout共享缓冲,但std::ifstream不受此开关影响,它始终走独立路径 - 若手动调用
std::ios_base::sync_with_stdio(false),只对cin/cout/cerr生效,不影响fread或ifstream::read - 想压榨极限吞吐?直接控制缓冲区:
setvbuf(fp, buf, _IOFBF, BUFSIZ)(fread)或file.rdbuf()->pubsetbuf(buf, size)(ifstream),但后者非标准行为,GCC/Clang 支持,MSVC 不保证
二进制读写时,fwrite(&x, sizeof(x), 1, fp) 和 file.write(reinterpret_cast(&x), sizeof(x)) 哪个更安全
都不绝对安全,但风险点不同:前者依赖 FILE* 的字节序和填充行为,后者依赖 reinterpret_cast 对 POD 类型的可移植性。
常见错误现象:fwrite 写结构体后,在另一平台读出字段错位;write() 读到未初始化内存,触发 UBSan 报告。
- 两者都要求目标类型是 trivially copyable(如
struct不能含虚函数、非 POD 成员、引用) -
fwrite不检查对齐,若结构体含#pragma pack(1),需确保两端编译选项一致 -
std::ofstream::write不抛异常,写失败时仅置failbit,必须手动检查!file或file.fail() - 跨平台序列化别用这两种——该上
protobuf或flatbuffers,而不是纠结fwrite多快
什么时候必须用 fread/fwrite,而不能用 C++ 流
只有两个真实理由:需要访问 FILE* 接口的第三方库(如 libpng、libjpeg、zlib 的 png_init_io),或要对接系统级 API(如 dup2(STDIN_FILENO, fileno(fp)))。
其他所谓“理由”基本是过时经验:比如“C 流更快”“C++ 流有异常开销”——现代编译器下,关掉异常、用 noexcept 版本,两者生成汇编几乎一样。
-
std::ifstream不支持fdopen或funopen这类底层 fd 绑定,FILE*可以 -
fread支持部分读(返回值可能小于请求长度),ifstream::read也是,但后者不会自动重试,需配合gcount()判断实际读了多少 - 调试时用
fileno(fp)查 fd 号,比从ifstream反查容易得多
真正容易被忽略的是:fread/fwrite 的返回值语义和 C++ 流不一致——前者返回“成功读/写的元素个数”,后者是流对象自身,得靠 gcount() 或状态位判断。混用逻辑时,这里最容易埋 bug。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











