最近在修改一个 C 的开源小项目。因为是想在 Win 下用的,但项目是用 autoconf 构建的,所以准备了 MSYS2 UCRT64 环境来开发。然后就踩了处理不了大于 2G 文件的坑(用了 fstat)。虽然说就是一个 _FILE_OFFSET_BITS 宏的事,但毕竟是个跨平台项目,所以就查了下主流系统下这个问题的支持情况,感觉好多槽点。
- MSYS MinGW-w64 默认提供 32 位 off_t ,哪怕你在编译 64 位程序,想用需要上面的宏,但这并不是 POSIX 标准化的东西
- autoconf 有一个 AC_SYS_LARGEFILE 可以自动判断是否需要定义宏,但 autoscan 没提示需要这个
- 如果是 32 位 target ,似乎默认提供 32 位 off_t 是天经地义的
- 不想跟环境打哑谜的可以用明确 64 位的方法,例如 fseeko64 fstat64 ,但这玩意并不普遍可用,还是要构建系统检测。 例如老版本 android 就不支持。bionic 的文档说一大堆考量,结果就是想解决你得用较新的 ndk ,放弃支持旧版 android ,或者就放弃支持 32 位 abi 。(所以实际上哪怕是 arm64-v8a 的 android 系统依然有机会在处理大文件时出问题)
- 哪怕你不关心文件大小也可能被影响,例如查个文件创建日期就要用到 fstat ,尽管觉得做的事跟大小无关但就是有影响
- 如果在 abi 边界用了这些带 off_t 的变量/struct ,显然会出现 abi 不兼容问题,你也不知道一个第三方库可能用哪种配置
个人觉得 2GB 以上大文件并不是什么很罕见的用例,为什么开发环境就不能默认支持这些情况呢,难道还影响兼容性?
标题里的“为未来准备好”是指,只使用跨平台的 C/C++,加上 2000 年后的 POSIX:
- 已解决 2038 问题
- 除非明确要求,否则文本存储和 IO 都是 UTF-8 且不使用 wchar_t
- 无论环境如何都能正确在 ui 或控制台输出非 ASCII 字符
- 不拒绝使用 IPv6
- 支持长路径
- 保持对近十年出厂的系统和硬件的支持
似乎要在无第三方依赖的情况下做到这个是很困难的事?