似乎在 C 的领域,让一个新程序“为未来准备好”是一件很麻烦的事 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
jim9606
V2EX    C++

似乎在 C 的领域,让一个新程序“为未来准备好”是一件很麻烦的事

  •  1
     
  •   jim9606 Apr 9 3062 views

    最近在修改一个 C 的开源小项目。因为是想在 Win 下用的,但项目是用 autoconf 构建的,所以准备了 MSYS2 UCRT64 环境来开发。然后就踩了处理不了大于 2G 文件的坑(用了 fstat)。虽然说就是一个 _FILE_OFFSET_BITS 宏的事,但毕竟是个跨平台项目,所以就查了下主流系统下这个问题的支持情况,感觉好多槽点。

    1. MSYS MinGW-w64 默认提供 32 位 off_t ,哪怕你在编译 64 位程序,想用需要上面的宏,但这并不是 POSIX 标准化的东西
    2. autoconf 有一个 AC_SYS_LARGEFILE 可以自动判断是否需要定义宏,但 autoscan 没提示需要这个
    3. 如果是 32 位 target ,似乎默认提供 32 位 off_t 是天经地义的
    4. 不想跟环境打哑谜的可以用明确 64 位的方法,例如 fseeko64 fstat64 ,但这玩意并不普遍可用,还是要构建系统检测。 例如老版本 android 就不支持。bionic 的文档说一大堆考量,结果就是想解决你得用较新的 ndk ,放弃支持旧版 android ,或者就放弃支持 32 位 abi 。(所以实际上哪怕是 arm64-v8a 的 android 系统依然有机会在处理大文件时出问题)
    5. 哪怕你不关心文件大小也可能被影响,例如查个文件创建日期就要用到 fstat ,尽管觉得做的事跟大小无关但就是有影响
    6. 如果在 abi 边界用了这些带 off_t 的变量/struct ,显然会出现 abi 不兼容问题,你也不知道一个第三方库可能用哪种配置

    个人觉得 2GB 以上大文件并不是什么很罕见的用例,为什么开发环境就不能默认支持这些情况呢,难道还影响兼容性?

    标题里的“为未来准备好”是指,只使用跨平台的 C/C++,加上 2000 年后的 POSIX:

    1. 已解决 2038 问题
    2. 除非明确要求,否则文本存储和 IO 都是 UTF-8 且不使用 wchar_t
    3. 无论环境如何都能正确在 ui 或控制台输出非 ASCII 字符
    4. 不拒绝使用 IPv6
    5. 支持长路径
    6. 保持对近十年出厂的系统和硬件的支持

    似乎要在无第三方依赖的情况下做到这个是很困难的事?

    22 replies    2026-04-11 04:33:27 +08:00
    Thymolblue
        1
    Thymolblue  
       Apr 9
    - 即使是 2026 年了,微软也没解决中文路径编码问题。我在程序里的字符串统一使用的是 UTF-8 编码,POSIX 下没有任何问题,但是在 Windows 下路径直接就识别不了。
    - 另外跨平台项目更推荐使用 CMake 提供构建支持。autoconf 依赖 bash 环境,不是所有设备都能够很容易安装的。
    - 现在很多开源的都库不支持编译成 32 位,32 位的系统也不常见了,不如直接只支持 64 位设备。
    pursuer
        2
    pursuer  
       Apr 9
    因为 C/C++跨平台本就不怎么样,autoconf 更是重量级,要跨平台就 libuv+CMake 。
    确实 2GB 以上大文件不算罕见,但就像你说的,这是 ABI 不兼容,对于 c/c++,兼容性更重要。虽然 Glibc 自己都做不好 ABI 兼容。
    xtreme1
        3
    xtreme1  
       Apr 9
    因为在 WINAPI / libc 层面是玩不了黑魔法的, 分分钟内存越界
    capric
        4
    capric  
       Apr 9
    你让 ai 把 autoconf 转换为 meson ,然后用 zig cc 当交叉编译器就很舒服
    penisulaS
        5
    penisulaS  
       Apr 9
    见过一个项目直接用 rust 写壳包 c 核,就是因为 posix 兼容太烦人
    changnet
        6
    changnet  
       Apr 9
    1. posix 是一套操作系统接口标准,而 C 是一门语言。写 C 不能按 posix 去写。就好比打包出来一个 apk ,老是有人问在 win 上为什么安装不了 apk 一样。
    1. posix 在 linux 下还行,但在 win 下就是不行。这个是微软的问题,它早年就是独立于 posix 的。后来 posix 用得广了才勉为其难加了兼容接口,但一直不怎么维护,和 posix 的兼容性也不太好。
    2. C/C++都是专注于语言而不是应用,它们所给的标准都是基于语言层面的。各个平台自己咋实现它不管。所以它的标准库接口很少,stl 也很少。很多功能必须用系统 api
    3. minGW 和 CyWin 这东西本来就冷门,维护也是跟不上的。我试过把 linux 上的程序迁移到 win ,想着用 CyWin 可以少改些。但实际勉强能跑起来但很难维护,第三方库大多没有官方支持,所以直接切换到 MSCV 了。
    4. C/C++现代一些的应该是用 CMake 的项目,autoconf 应该是 linux 下的项目了。

    C/C++因为历史的原因,它就是没法做到像其他语言那样跨平台 api 统一的。如果是新项目,用 cmake + 新标准(比如 C++ 17 以上)可以解决 90%的问题,比如你说的用 C++的 std::filesystem 应该是可以的。剩下的 10%用各自原生的平台接口维护(比如网络接口)。

    但你是旧项目,要么全改,要么写各种兼容
    Mithril
        7
    Mithril  
       Apr 9   1
    所以“新程序”已经尽量不用 C/C++来写了,特别是如果你的程序想要跨平台的话,项目做大了就会发现到处都是坑。

    更别说你做个开源项目了,大半精力都要花在维护这些乱七八糟的编译环境上。
    Mithril
        8
    Mithril  
       Apr 9
    另外基于我之前做的调查结果,最省心最简单的 C++跨平台,就是你只针对 Windows 开发,然后各种*nix 全用 Wine/Proton 去跑。

    Wine 上面的 API 兼容需要测试,你用到一些奇怪的 API 很可能在 Wine 上跑不通。不过但凡能跑通,绝对比你去每个平台维护一套编译,测试,要容易太多了。测试通过以后把 Windows 的二进制扔进去直接跑。

    有人说 Wine 是各种 Linux 上最稳定的 ABI 不是没有道理的。各种发行版你要都支持,光是 glibc/Musl 都能搞你一下。

    缺点就是这项目维护最好的只有游戏能用得到的那些 API ,如果你的程序还要调用别的 API ,比如硬件相关的,那就没办法了。
    capric
        9
    capric  
       Apr 9
    @penisulaS 我就是这样的,这样上层 rust 用 cargo-zigbuild 交叉编译,底层 c 也一起交叉编译
    capric
        10
    capric  
       Apr 9
    @capric 还把 rust 数据结构暴露给 c 用
    Ketteiron
        11
    Ketteiron  
       Apr 9
    Rust 会流行,有很大原因就是 C/C++ 这些狗屁倒灶的事情无法解决。
    根本原因还是 ABI ,C/C++ 选择绝对的向后兼容,代价就是历史遗留问题几乎无法处理; Rust 非常激进走了另一条路,不提供任何稳定 ABI ,因此清理历史包袱的代价非常轻。但是,哈哈,Rust 有稳定的 C ABI 。
    要我说,还是 C++ 太贪婪了,既想要一切抽象和范式,又想要保证向后兼容,还得为 n 个平台擦屁股,根本是做梦。
    目前最务实的做法还是 Rust + C ,两个语言都有各自的破事,不如合起来只用最好的部分。
    xuanbg
        12
    xuanbg  
       Apr 9
    直接让 AI 翻译成 rust 好了
    WorseIsBetter
        13
    WorseIsBetter  
       Apr 9   1
    我的个人项目(参考我发的第一个主题帖)也有处理 32-bit/64-bit 的 off_t/time_t 。我觉得这块其实是很 trivial 的,没你说的那么复杂。

    原则只有一条:管好自己的项目就行。

    你的代码里需要意识到这些类型有 32-bit 和 64-bit 两种可能,并且分别对其做支持(或者不对某些情况做支持并让构建过程失败),就足够了。至于和其他程序的 ABI 兼容,是由发行版的包维护者或者用户自己(如果他们选择自行构建)来保证的。

    除此之外,你唯一能做的,大概只有把构建脚本写得更灵活、优雅,再配上清晰明确的构建文档,让包维护者和用户少走或不走弯路。

    另外:不建议依靠 autoscan ,那玩意只起到一个基本的示例作用,对实际项目的帮助不大。还是得想清楚自己具体需要在 autoconf.ac 中检查什么、配置什么,然后根据需求来写
    xiliuya
        14
    xiliuya  
       Apr 9
    不要用 windows 就可以完美解决这个问题,不是 c/c++的问题,而是 win 的锅。
    beautyplus
        15
    beautyplus  
       Apr 9
    本质还是编码对不上,跟 windows 系统 **交互** 是要尽量用 wchar 的,尤其是带路径参数的函数比如 wfopen ,CreateFileW ,因为你不确定目标机器有没有开启 utf-8 (区域设置中的使用 utf-8 还标记着 beta 默认不勾选)
    cnbatch
        16
    cnbatch  
       Apr 9
    这是 C 的事情,发到 C++板块不怎么妥当吧

    前半部分

    1 ,这是 MSYS MinGW 的锅,它们没处理好 64 位的适配。Windows 提供了 fseeko64 的替代品 _fseeki64(),中间转换层本该做好映射支持的。
    2~6 ,这就是系统 API / SDK 的锅,包括 Android

    至于换语言能“解决”这些锅,本质上只是它们在标准库里面帮忙擦屁股而已。


    「为什么开发环境就不能默认支持这些情况呢,难道还影响兼容性?」

    开发环境当然可以默认支持这些情况,正常 POSIX 环境、正常 MSVC 环境直接写程序调用标准库 API 都没问题。
    没做到默认支持,很多时候完全是疏忽 (MSYS MinGW),或者是怕麻烦、赶进度(Android 5.0~6.0)。


    后半部分

    1 、若是 OS Level 的限制,编程语言本身能做的事情其实很有限。如果 OS 本身没解决 2038 问题,只要系统关机、重新开机,系统时间直接就是乱的,再完善的编程语言都没办法强行掰回来。
    若 OS Level 已经解决了 2038 问题,那么无论是 C 还是 C++,都不需要担心这种事。

    2 、纯 POSIX 可以。跨平台跨到 MSYS MinGW 的话,按理说 MSYS MinGW 应当处理好相应转换(像是背后处理编码调用带 W 的 API 、检测目标 Windows 有没有启用 UTF-8 区域选项),但这就不是普通使用者可以强制要求的了。

    3 、这就有点霸道了,别 C 语言、C++,哪怕是 Python 都没法如此保证。

    4 、单纯“不拒绝使用”的话,那还是不需要担心。如果想要更高要求达到“表现一致”,那就不太可能了。
    Linux 的 IPV6_V6ONLY 默认为 false ,而 BSD 和 macOS 还有 Windows 的 IPV6_V6ONLY 默认是 true 。
    OpenBSD 更是搞起了内部限制,无论 IPV6_V6ONLY 设成什么值,它都按照 true 处理。

    5 、类似 2

    6 、支持近十年出厂的系统很合理。但硬件??这可不是编程语言可以掌控的吧,这是 OS 和驱动程序的责任啊。
    adoal
        17
    adoal  
       Apr 9   1
    文件系统和其它需要 text label 的 API 支持 Unicode 用什么模式只是一种选择而已。Unix 世界为了兼容标准 C 库的字符串 0 结尾语义而选择了 UTF-8 locales ,Windows 为了不破坏已有的 MBCS locales 里的编码语义而选择了用双模 API ,本来就是不同理念,各有优缺点。没理由 POSIX 的做法比 Windows 更正确或更“标准”。
    xyx0826
        18
    xyx0826  
       Apr 10 via iPhone
    参见 [jart/cosmopolitan]( https://github.com/jart/cosmopolitan) 项目,一个让 C 语言一次编译、到处运行的库。现支持 Windows, Linux, macOS, *BSD 。UTF-8 读写支持也包含在内,例:[romanize.c]( https://github.com/jart/cosmopolitan/blob/master/examples/romanize.c)

    这是我所知的最接近你要求的项目。
    xyx0826
        19
    xyx0826  
       Apr 10 via iPhone
    附:redbean 是同作者基于 Cosmopolitan C 开发的一个跨平台 web server, 本身还是一个 zip 包用来装 lua 脚本和静态资源。

    https://redbean.dev/
    cnbatch
        20
    cnbatch  
       Apr 10
    多说一句,如果换了“其他语言”写程序手动调用 POSIX API ,照样会遇到一模一样的情况
    手动调用 Win32 API 同理(例如 rust winrt )
    jim9606
        21
    jim9606  
    OP
       Apr 11
    @changnet
    主要是 c 标准缺太多 os 功能了,posix 是相对中立又是 os 提供的东西,在 c/c++标准化吵完细节之前也只能这么干了

    @Ketteiron
    C/C++也没说绝对向后兼容,更多时候是新旧 abi 都给你留着(例如 libstdc++的 c++11 双 abi ,可以用新库原地替换),但还想新旧 abi 之间互操作就不现实了

    @beautyplus
    我目前的感觉是,就算用了 SetConsoleCP 和 win10 1903 增加的 activeCodePage manifest ,还是无法避免依赖系统全局 utf-8 开关,必须走 wchar 那一套

    @cnbatch
    1. 我知道有些系统受 y2038 影响,但工具链应该有条件做到尽力支持,例如,默认行为就是 64bit time_t ,允许最低限度 opt-out 来解决历史兼容
    2. 我是没明白为啥都弃坑 mingw32/clang32 了还没解决这个问题,可能单纯没人搞?
    3. 预期是依赖 win 系统的自动转换,程序可以不依赖全局 utf-8 开关的状态也能正确显示中文愉快地用窄字符 C/C++,CPython UTF-8 mode 算是相当接近这个目标了
    4. 那还行,至少应用侧有方便 opt-in 的方法
    6. 因为很多时候会出现新硬件搭配旧系统的情况,出货时间往往决定应用何时无条件停止支持。例如 Intel/AMD 已经停止出货不支持 AMD64(NX,SSE2)的 x86 CPU 相当长的时间,所以主流应用和工具链基本都不考虑不支持 NX/SSE2 的情况了,但 android 这边因为依然有 armv7 的 SoC ,或者 armv8 SoC 搭配 32 位 os 的硬件在出货,所以无论系统还是工具链短期内都不太可能弃坑
    cnbatch
        22
    cnbatch  
       Apr 11
    2038 问题由工具链兜底实在是强人所难了,毕竟作用很有限。即使工具链给了 64 位 time_t 在内部做转换,到了 OS 层面给出的时间直接就是错的,工具链再怎么兜底都没用。这就好比寄信人提供的门牌号直接就是错的,就算印门牌号的纸足够容纳都没用。

    MinGW 那边可以认为是没人搞,长期以来进度缓慢,无解

    这个有折中做法,chcp 65001 即可解决。也可以主动调用 SetConsoleCP 和 SetConsoleOutputCP 。

    Android 的事情,老实说,那得看 Google 的脸色了。编译器开发者或许能够解决二进制文件生成的支持,但 SDK 的更新就无能为力了。若 Google 决定停止向旧版系统提供新版 SDK (无论 C/C++还是 Java/Kotlin ),无论给多少钱都不行,那也不可能拿起武器对准 Google 大楼要求他们继续更新的吧。这个责任,不是某一个编程语言能够承担的。除了 Google 自己,其他人拿它没办法。顶多只能靠开源社区自己打 patch 做更新。
    打个比方,这就相当于要求在 Linux 4.x 使用 io_uring 的 API ,编译时发现不存在然后责怪编程语言和工具链,属于怪错对象了。想要用不是不行,这得有人愿意做 backport ,但这显然不是编程语言和工具链的责任了。
    About     Help     Advertise     Blog     API     FAQ     Solana     1060 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 73ms UTC 23:34 PVG 07:34 LAX 16:34 JFK 19:34
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86