C++的两大阵营
摘要
本文探讨了C++社区内部关于ABI破坏和内存安全性的冲突,同时涉及政府警告以及大型科技公司转向Rust的趋势。
暂无内容
查看缓存全文
缓存时间: 2026/08/19 10:29
# C++的两大阵营
来源:https://herecomesthemoon.net/2024/11/two-factions-of-cpp/index.html
Zero Ranger.Zero Ranger\.切换原图/抖动图
关于C++的未来,似乎存在大量的争论与分歧。
无论是在Reddit还是某个橙色网站(指Hacker News),当然也一定是在C++标准委员会的官方会议上。这无需深究。
**编辑于2024年11月25日:** 修正了错别字和措辞。在HN (https://news.ycombinator.com/item?id=42231489)、r/cpp (https://www.reddit.com/r/cpp/comments/1gyxhss/the_two_factions_of_c/)、lobste.rs (https://lobste.rs/s/owmlgx/two_factions_c) 上有提及。
## C++的绝对现状
目前的情况似乎是:
- C++的演化工作组 (EWG) 刚刚就采纳 P3466 R0 - (重新)确认未来C++演化的设计原则 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3466r0.pdf) 达成共识 (https://github.com/cplusplus/papers/issues/2121#issuecomment-2494153010):
- 这意味着不破坏ABI(二进制接口兼容性),保留与C及之前C++版本的链接兼容性。
- 这也意味着没有“侵入性标注”(例如,没有生命周期标注)¹ (https://herecomesthemoon.net/2024/11/two-factions-of-cpp/index.html#fn:1)
- 它坚持一套互不兼容的目标,即不破坏ABI和零开销原则² (https://herecomesthemoon.net/2024/11/two-factions-of-cpp/index.html#fn:2)。
- 无论好坏,这都是对C++语言当前发展路径的(字面意义上的)加倍坚持。
与此同时:
- 美国政府希望人们停止使用C++:
- CISA (https://www.cisa.gov/resources-tools/resources/product-security-bad-practices)
- NSA (https://media.defense.gov/2022/Nov/10/2003112742/-1/-1/0/CSI_SOFTWARE_MEMORY_SAFETY.PDF)
- 还有白宫,显然。(https://www.whitehouse.gov/wp-content/uploads/2024/02/Final-ONCD-Technical-Report.pdf)
- 是的,没开玩笑。美国政府的多个分支机构已发布文件、报告和建议,警告业界不要使用内存不安全的语言。
- 各大科技公司正在采用Rust:
- 微软显然正在用Rust重写核心库 (https://www.theregister.com/2023/04/27/microsoft_windows_rust/)。
- Google似乎正致力于采用Rust (https://security.googleblog.com/2021/04/rust-in-android-platform.html),并且实际上已开始开发双向C++/Rust互操作工具 (https://github.com/google/crubit)。
- AWS正在使用Rust (https://aws.amazon.com/blogs/devops/why-aws-is-the-best-place-to-run-rust/)。
- 等等。
- 提到科技巨头,你注意到Herb Sutter正在离开微软 (https://herbsutter.com/2024/11/11/a-new-chapter-and-a-pivotal-year-for-cpp/)了吗?并且MSVC似乎在实现C++23特性上进展缓慢,还在向社区征求优先级建议 (https://www.reddit.com/r/cpp/comments/1gkdr6e/msvc_c23_support/)。
- 那场臭名昭著的布拉格ABI投票 (https://cor3ntin.github.io/posts/abi/) 已经发生(简而言之:“C++23不会破坏ABI,未来是否会发生也不清楚”),Google据称大幅减少了其在C++开发过程中的参与,转而开始开发他们自己的C++后继语言 (https://www.youtube.com/watch?v=omrY53kbVoA)。他们甚至有一份总结 (https://github.com/carbon-language/carbon-lang/blob/trunk/docs/project/difficulties_improving_cpp.md) 概述了他们在改进C++时遇到的所有问题³ (https://herecomesthemoon.net/2024/11/two-factions-of-cpp/index.html#fn:3)。
- 社区中广泛流传并分享着人们多年努力参与C++标准委员会流程,最终却被消耗殆尽的故事 (https://thephd.dev/finally-embed-in-c23)。(一项特性先在*C*中落地也无济于事。)
- 模块仍未实现。我们有模块了吗?(https://arewemodulesyet.org/)⁴ (https://herecomesthemoon.net/2024/11/two-factions-of-cpp/index.html#fn:4)
- “安全配置文件” (https://isocpp.org/files/papers/P3081R0.pdf) 仍处于一种奇怪的状态,没有现有实现,试图在最小化现有代码改动的前提下,为现有C++代码注入*一定程度*的安全性。Sean Baxter本人表明了反对配置文件的立场 (https://www.circle-lang.org/draft-profiles.html),并将C++描述为“规范不足”。
- 如果你继续深挖,会发现更多来源,例如一位读者写并分享给我的这份报告/分析 (https://bohdanqq.com/docs/safety-cpp-cultures.pdf)。
我不知道你怎么想,但如果我*作为局外人*来看待这一切,这确实看起来像是C++正在*分崩离析*,并且似乎有大量的人对C++委员会*无论如何*都能掌控局面的能力失去了信心⁵ (https://herecomesthemoon.net/2024/11/two-factions-of-cpp/index.html#fn:5)。
## 两种文化
人们似乎在寻找其他解决方案。
比如说Google。显然,自ABI投票以来,Google就对“这个流程”失去了信心。这不是对语言本身失去信心,Google拥有世界上最大的C++代码库之一,并且它为他们提供了极好的服务。这是在不同压力(潜在的政府监管、竞争语言、关键参与者对更好性能和安全性的需求等)下,对语言演化能力的信心丧失。
那么问题出在哪里?为什么C++就是……不改变呢?
嗯,弄清楚这个很容易。只需看看Herb Sutter在关于配置文件的论文 (https://isocpp.org/files/papers/P3081R0.pdf) 中说了什么:
> “**我们必须最大限度地减少更改现有代码的需求。**对于在现有代码中的应用,几十年的经验一致表明,大多数拥有大型代码库的客户不会、也不可能为了满足严格性规则而更改其哪怕1%的代码行,除非有监管要求强迫他们这样做,即使是为了安全原因也是如此。” – Herb Sutter
很酷。有人对此感到惊讶吗?我不这么认为。
现在,让我们将此与Chandler Carruth在WG21成员页面上的简介 (https://isocpp.org/wiki/faq/wg21#chandler-carruth) 进行对比:
> 我领导了**基于Clang构建的C++工具和自动化重构系统的设计**,现已成为Clang项目的一部分。[...] 在Google内部,我领导了将**基于Clang的自动化重构工具**扩展到我们整个代码库的努力,超过1亿行C++代码。我们可以在20分钟内分析并应用整个代码库的重构。
哦。你看到了吗?(是的,你看到了,我把它标出来了。)
是“自动化工具”。只不过它不仅仅是*那样*,自动化迁移工具只是其巅峰,是唯一闪亮的例子。
我们基本上看到了C++用户之间两个截然不同阵营的冲突:
- 相对现代、有能力的科技公司,它们明白自己的代码是一种资产。(这严格来说不一定是*大型*科技公司。任何理性的、使用全新C++的初创公司也会属于这一类。)
- 其他所有人。每个仍在为代码缩进方式而争吵的古老公司,以及每个乞求管理层允许安装代码检查器的年轻工程师。
其中一个群体将能够*相对*优雅地处理迁移,那就是能够**从版本化源代码构建其C++技术栈**的群体,而不是仍在使用1998年古老预编译库的群体。
这种从版本化源代码(最好是带有自动化测试)构建整个依赖栈的能力,可能是划分这两个阵营最关键的分界线。
当然,在实践中,这是一个渐变过程。我只能想象,将大型科技代码库从可怕的“泥球”转变为半可管理、可构建、有代码检查、版本控制良好、稍微不那么可怕的“泥球”,必然耗费了多少汗水、泪水、账单和鲜血。
事后看来,很容易认为这一切都是不可避免的:像Google这样使用相对现代C++、拥有自动化工具和测试以及现代化基础设施的公司的需求,与对向后兼容性的(非常强烈的)渴望之间,存在明显的脱节。
大胆地说,单一、无方言、统一的C++的概念似乎**已经死了多年**⁶ (https://herecomesthemoon.net/2024/11/two-factions-of-cpp/index.html#fn:6)。我们至少有两种主要的C++流派:
- 任何*稍微*现代的C++。所有代码都可以通过某种专用、干净且统一的构建流程(至少比原始CMake稍微复杂一点)从版本化源代码构建,并且如果你眯起眼睛看,感觉它就是能工作。某种静态分析器、格式化工具、代码检查器。*任何*关于保持代码库干净且现代是有价值的共识。可能至少是C++17,包含`unique_ptr`、`constexpr`、lambda表达式、`optional`,但*重点不在于此*。重要的是工具链。
- 遗留C++。除此之外的任何东西。任何存在于中小型银行古老、积灰服务器上的C++。任何依赖于某个完全过时的编译代码块的C++,其源代码已丢失,原作者也无法联系。任何部署在“宠物型”服务器(即需要精心维护)上的C++,以至于在其他地方启动它需要工程师花费整整一个月时间来弄清楚所有隐式依赖、配置和环境变量。任何主要被归类为成本中心的代码库。*任何从源代码构建所用二进制文件需要按多个按钮、或者根本不可能完成的代码。*
你会注意到主要区别根本不在C++本身。区别在于*工具链*以及以任何干净、明确的方式从版本化源代码构建的能力。理想情况下,甚至包括*部署*的能力,而无需记住前任通常设置以防止一切崩溃的那个标志或环境变量。
例如,Google的代码库中有多少遵循“现代”C++习惯用法,这远不如工具链是否良好、以及能否从源代码构建重要。
很多人会告诉你,工具链不是C++标准委员会的责任,*他们是对的*。工具链不是C++标准委员会的责任,*因为C++标准委员会放弃了对此的任何责任*(它专注于C++语言的规范,*而非*具体实现)⁷ (https://herecomesthemoon.net/2024/11/two-factions-of-cpp/index.html#fn:7)。这是设计如此,考虑到历史包袱,也很难责怪他们。C++是一个统一不同实现的标准。
话虽如此,如果说Go做对了一件事,那就是它认识到了工具链的重要性。相比之下,C++还停留在代码检查器发明之前的史前时代。C++没有统一的构建系统,甚至没有任何接近统一的包管理系统,它极难解析和分析(这对工具链来说*是灾难*),并且对于需要进行的每一项更改,都在与海勒姆定律(Hyrum's Law)进行着一场可怕的艰苦战斗。
这两个阵营(工具链良好、可以从源代码轻松构建 vs 工具链糟糕、无法从源代码构建)之间存在着巨大且不断扩大的鸿沟,老实说,我看不出它近期有弥合的迹象。
C++委员会似乎相当致力于(可以说,是*执着于*)维护向后兼容性,不惜一切代价。
顺便说一句,我并非不同意这一点!向后兼容性对许多人来说都是*极其重要*的,理由非常充分。其他人则不那么在乎。哪个群体“正确”并不重要:关键在于这些是不相容的观点。
## 后果
这就是为什么配置文件会是现在的样子:安全配置文件*并非*旨在解决现代、技术娴熟的C++公司的问题。它们旨在*不*要求对旧代码做任何改动的情况下带来改进。
模块也是如此。设计上应该可以“直接”将头文件作为模块导入,并且不应该有任何向后兼容性问题。
当然,*所有人都*喜欢那些可以即插即用、无需更改旧代码就能带来改进的功能。但很明显,这些功能(首先)是为“遗留C++”的目标而设计的。任何需要从遗留C++迁移的功能,对于C++委员会来说都是不可能的,因为正如Herb Sutter所说,你基本上不能指望人们去迁移。
(同样,以“遗留C++”为前提来构建功能并非坏事。这是一个完全明智的决定。)
这是我查阅C++论文时尽量牢记的一点:这里有两个庞大的受众群体。一个是现代C++的,另一个是遗留C++的。这两个阵营激烈争论,许多论文都是针对其中特定群体的需求而写的。
这显然导致了许多人各说各话:尽管人们认为,安全配置文件和安全C++ (Safe C++) 试图解决的是*完全不同的问题,面向不同的受众*,而不是相同的问题。
C++委员会正试图阻止这种分歧扩大。这大概就是为什么像Sean Baxter的安全C++ (https://safecpp.org/draft.html) 这样的东西对他们来说是不可能的。这是一项根本性的、全面的变革,可能会创造出一种全新的C++编写方式。
当然,还有一个问题:某些C++标准委员会成员是否只是非常、非常固执,并且为了阻止他们个人在审美上不认同的演进而拼命抓住救命稻草。
我无意指责任何人,但这并非我第一次听说C++委员会应用双重标准,例如:“我们期望你提供一个完整的、可在多个主流编译器上工作的实现,才能看到这个提案获得批准,但我们仍然乐于致力于某些庞大的项目(例如模块、配置文件),而这些项目甚至没有功能性的概念验证实现。”
如果*情况确实如此*(我真的不知道),那么我真的不知道C++还能在没有发生更剧烈分裂的情况下,在这条路上走多久。
而所有这一切,甚至还没有触及破坏ABI兼容性可能引发的巨大麻烦和问题。
相似文章
Rust与C/C++在内存安全CVE上的差异
分析Rust与C/C++在内存安全CVE报告方式上的不同,论证即使存在错误,Rust的设计也能降低某些类型漏洞的发生。
反对C语言替代方案的理由(2022)
本文反对用替代方案取代C编程语言,并强调了工具链成熟度、语言不确定性、开发者资源有限性和C ABI兼容性问题等挑战。
内存安全绝对主义者
本文批评了编程语言辩论中的内存安全绝对主义,认为像 Fil-C 这样的新方法也有权衡,而将 Rust 视为不安全忽略了实际好处。
为何常见的Rust包依赖C代码?(2023)
本文探讨为何许多常见的Rust包依赖于C代码,可能讨论技术原因及其对生态系统的影响。
To Save C, We Must Save ABI
The author argues that despite the common call to break ABI to save C++, preserving a stable ABI is necessary to allow C to evolve, and discusses the trade-offs and constraints ABI stability imposes on language and standard library improvements.