你(可能)不需要学习 C
“现代程序员大概不需要学习 C”的说法引发了关于低层知识在高效编程中到底有多必要的争论。许多人认为,C(或类似的系统语言)对于理解内存、性能以及更高层语言背后的抽象至关重要;也有人反驳说,真实硬件行为如今远比 C 的模型复杂得多,而且大多数职业生涯并不依赖它。讨论凸显了深度与广度之间的取舍:学习时间有限、C 本身的复杂性与陷阱,以及能够读取或推理大量基于 C 的现有系统代码的实际好处。
范围:你“需要”学习 C 吗?
- 许多人同意,成为一名高效、甚至“优秀”的程序员并不需要 C;很多现代工作完全可以只用更高层的语言完成。
- 也有人主张要“全面一些”:至少了解一种系统语言(通常是 C、C++、Rust、Zig)能让你对软件有更广阔的理解。
- 还有人反对“每个人都必须学 C”的说法;另一些人则认为时间有限,而 C 可能并不会带来人们想象中的那些收益。
C 与“计算机到底是怎么工作的”
- 一种观点认为:C 已经不能很好地反映现代硬件(流水线、缓存、分支预测、多核、虚拟内存、微码),所以它并不能真正展示“计算机是如何工作的”。
- 反方观点是:C 仍然比 Python/JS 更直接地映射到硬件/操作系统行为,而且在用户态里,除了汇编之外它已经算是“最低层了”;学习它能让人对内存、布局和性能形成有意义的直觉。
- 也有人指出,没有任何语言能真正暴露现代硬件的所有细节;即使是汇编也会隐藏一些层次。
内存模型、指针与未定义行为
- 围绕 C 是否会让人把内存想成“一个巨大的字节数组”展开了长时间争论。
- 有人说:那只是一个抽象模型;操作系统、MMU、虚拟内存和分段会打破这种直觉。
- 也有人说:在对象/数组内部,C 确实保证虚拟上的连续性;物理布局与抽象机器无关。
- 讨论进一步区分了:
- C 的并发内存模型(stdatomic)与不那么正式的“内存看起来是什么样”。
- 实现定义行为(例如 int↔pointer 转换)与未定义行为(例如越界访问、某些指针生命周期问题)。
- 指针被描述为概念上简单、实践上却很危险:它是 bug、UB 和安全问题的主要来源。
学习 C 的实际原因
- 阅读和修改大型现有 C 代码库(内核、数据库、库、嵌入式代码)。
- 理解更高层语言使用的底层构件:分配、栈/堆、结构体、虚表、引用计数、FFI 边界。
- 与那些“用 C 思考”或用系统抽象思考的同事交流。
替代方案与教学观点
- 有人建议,像构建 VM/编译器或 nand2tetris 这样的课程,可能比“学习 C”更适合作为理解系统的路径。
- 也有人喜欢把 C 作为教学工具,因为你必须自己实现数据结构(map、vector、string),从而暴露出在更高层语言中被隐藏的成本。
- 工具链上的痛点(Make/CMake、多平台构建)被认为是其相较于 Rust/Go 这类集成工具链的一个缺点。