编程与软件工程chiark.greenend.org.uk编辑精选
沉入 C 语言
The descent to C
2014 — 2021,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
Simon Tatham(PuTTY 作者)写给习惯高级语言的程序员的 C 语言剖析文章,逐层下降到 C 的底层模型:数组与指针的等价关系、字符串与手动内存管理的麻烦,以及 C 为何显得古怪。它不是语法大全,而是解释 C 的思维方式与历史/机器约束。
为什么经久不衰:它把 C 的“怪”拆成可理解的底层现实与历史取舍,二十多年来仍是理解指针、内存和底层编程的经典入口。
HN 评论精选
反驳“C 如此是因为现实如此”:手动内存管理和简化内存模型是设计选择,不是机器本质。
文章不错,但我不同意这一段:C 之所以这样,很大程度上是因为现实就是这样……不完全是。C 在处理字符串和指针时的很多复杂性,是因为没有垃圾回收。但它有 malloc()/free(),这并不比垃圾回收器更根本或更接近机器;一个简单的 GC 并不比简单的手动堆实现复杂多少。而且 C 的计算模型是对“现实”的巨大简化。“现实”中的机器每个时钟周期能执行 3-4 条指令和 1-2 次加载,有多个不同大小和性能特征的内存层级,能乱序处理请求,多处理器上还有复杂的缓存一致性协议。C 呈现的是一个简单的“一大块字节数组”内存模型,把这一切都抽象掉了……
rayiner查看英文原文
The article is good, but I disagree with this part: "To a large extent, the answer is: C is that way because reality is that way. C is a low-level language, which means that the way things are done in C is very similar to the way they're done by the computer itself. If you were writing machine code, you'd find that most of the discussion above was just as true as it is in C: strings really are very difficult to handle efficiently (and high-level languages only hide that difficulty, they don't remove it), pointer dereferences are always prone to that kind of problem if you don't either code defensively or avoid making any mistakes, and so on." Not really, and not quite. A lot of the complexity of C when it comes to handling strings and pointers is the result of not having garbage collection. But it does have malloc()/free(), and that's not really any more fundamental or closer to the machine than a garbage collector. A simple garbage collector isn't really any more complicated than a simple manual heap implementation. And C's computational model is a vast simplification of "reality." "Reality" is a machine that can do 3-4 instructions and 1-2 loads per clock cycle, with a hierarchical memory structure that has several levels with different sizes and performance characteristics, that can handle requests out of order and uses elaborate protocols for cache coherence on multiprocessor machines. C presents a simple "big array of bytes" memory model that totally abstracts all that complexity. And machines go to great lengths to maintain that fiction.
C 的魅力在于尽量不碍事,给程序员直接控制权;作者结尾低估了这种主动选择。
职业 C 程序员路过……这些观点很好,对想理解 C 思维方式的人来说是很好的入门。不过结尾有点偏。作者像是在说“C 因为历史原因古怪而粗糙,有些人用只是因为守旧”。我写内核驱动,但我也就是喜欢用 C,就像我喜欢开手动挡、通常关掉车上的安全辅助:C 非常努力地不挡你的路。我也喜欢写 Ruby 和 JavaScript,但有时会想“这里多了一次不必要的拷贝……这很低效……如果用 C 写我就不用这样”。(当然也有“这一行代码要写成 100 多行 C”的时候,先不提了……)
nathanb查看英文原文
Professional C programmer here... The points are great and this is generally a good primer for someone who wants to understand the C mindset. The bit at the end is a bit off, though. It feels like the author is saying "yeah, C is weird and crufty for historical reasons and some people just use it because they're backward like that". Yeah, I write kernel drivers, but I also just plain like using C, for the same reason that I like driving a manual transmission and usually disable the safety features on stuff: C tries really hard to not get in your way. I enjoy programming in Ruby and mostly enjoy programming in Javascript. But there are times when I think "this is an unnecessary copy...this is inefficient...I wouldn't have to do this if I were writing in C". (There are also times where I think "this one line of code would be over 100 lines of C", but we won't get into that right now...).
在极端受限的嵌入式环境里,C 工具链能精细控制二进制大小和链接方式,这是难以替代的能力。
最近我要为一个跑在 MIPS 架构、只有 2MB flash 的嵌入式 Linux 路由器写程序,应用只有约 40KB 空间。我通过 GCC 技巧——分离数据和代码段、删除无用段、部分库静态链接、部分动态链接——把原本编译出来超过 1.5MB 的二进制压到 20KB。这再次让我非常感激:有这样一种语言和工具链,能在职业生涯可能依赖的那 1% 问题上给你这种能力。附上最终 Makefile 的相关片段供一乐……我不确定还有多少其他语言/工具链能在链接层面给你这种灵活性。而且它是自包含的,不需要某种虚拟机或解释器来运行。
laichzeit0查看英文原文
Recently I had to write a program for an embedded Linux router which ran on a MIPS architecture and had a 2MB flash. I only had about 40kb of space to fit the application on. I was able to get a binary that was compiling to more than 1.5mb down to 20kb through using a combination of gcc tricks like separating data and code sections, eliminating unused sections, statically linking some libraries and dynamically linking against others. It once again gave me immense appreciation for having a language and toolchain that can give you this power for those 1% of problems your career might depend on. For amusement, the relevant section of the Makefile I ended up with: LIB_NL_MIPS_STATIC=libs/libnl_mips_static CFLAGS=-Os -I$(LIB_NL_BASE)/include -ffunction-sections -fdata-sections -Wall -Wextra -MD LDFLAGS=-Wl,--gc-sections -L$(LIB_NL_MIPS_STATIC) -Lbuild -Wl,-Bstatic -lmon -lnl-3 -lnl-route-3 -Wl,-Bdynamic -lpthread -lm -lc I'm unsure how many other languages/toolchains give you that sort of flexibility down to the linking level. Also it's self contained and doesn't require some kind of "virtual machine" or interpreter to run it.
C 的痛苦内存模型源于早期编译器体积限制,并非底层语言的必然;带长度数组/切片本可兼容地加入。
C 是底层语言,并不必然意味着要有这么痛苦的内存模型。这是当年为了把编译器塞进按现代标准极小的机器而造成的后果。最初连函数原型都没有。我曾提出过一个向后兼容的 C 改进方案:基本上,你可以把数组当作带长度的对象来谈论,即使长度在另一个变量里;并且得到切片和引用。讨论充分到足以证明可行,但推动它前进的努力不值得。切片很重要,它能做大多数人们用指针算术做的事;有了大小和切片,你仍然可以在接近内存地址的层面操作。
Animats查看英文原文
It's not inherent in C being a low-level language that it has such a painful memory model. It's a consequence of having to fit the compiler into a really tiny machine by modern standards. Originally, there were no function prototypes. I once proposed a backwards-compatible way out for C.[1] Basically, you get to talk about arrays as objects with a length, even if that length is in some other variable. And you get slices and references. It was discussed enough to establish that it could work, but the effort to push it forward wasn't worth it. Slices are important. They let you do most of the things people do with pointer arithmetic. Once you have size and slices, you can still operate near the memory address level. [1] http://www.animats.com/papers/languages/safearraysforc43.pdf
历次讨论
同类还值得读
开源应用架构
The Architecture of Open Source Applications
《开源软件架构》(AOSA)是一本在线免费书,邀请知名开源项目的作者亲自剖析其内部设计,涵盖 SQLAlchemy、LLVM、Audacity、Apache、Bash 等系统。
编程与软件工程上首页 9 次 · 2011–2024aosabook.org编辑精选编程语言简史:简短、不完整且多半错误
A Brief, Incomplete, and Mostly Wrong History of Programming Languages
一篇以戏谑、故意不准确的方式回顾编程语言史的博客文章,用夸张轶事和讽刺定义串起 Lisp、C、C++、Java、JavaScript、PHP 等语言。
编程与软件工程上首页 8 次 · 2009–2021james-iry.blogspot.comSQLite 是如何测试的
How SQLite is tested
SQLite 官方文档页,系统介绍 SQLite 的测试体系:多种测试方法(TCL 测试、模糊测试、回归测试、静态分析等)和海量测试用例,展示了这个小型开源项目如何靠极致测试获得…
编程与软件工程上首页 8 次 · 2009–2025sqlite.org编辑精选高级编程语言(2009)
Advanced programming languages (2009)
Matt Might 的经典文章,按用途推荐“高级编程语言”:如果追求就业就选主流语言,如果追求表达力、学术研究或创业,则推荐 Haskell、OCaml、Scala 等函数式语…
编程与软件工程上首页 8 次 · 2009–2022matt.might.net我的 Forth 与栈机器经历
Yosefk - My history with Forth & stack machines
作者以亲身经历回顾了使用 Forth 语言和栈式机器的历程:既赞叹其简洁优雅、代码量小、可自举的优点,也坦率指出栈操作在实际编程中的痛苦,以及 Forth 社区文化中的问题。
编程与软件工程上首页 8 次 · 2010–2024yosefk.com编辑精选