C/C++编译器是如何工作的?

35

经过十多年的C/C++编程,我发现一个模式 - 非常优秀的程序员往往精通编译器的内部知识。

我是一名相当不错的程序员,拥有一些编译器的“迷信”,所以我想重新学习并从基础开始。

是否有人可以推荐在线资源或喜爱的书籍?我特别关注于C/C++编译、优化、GCC和LLVM方面的知识。


4
请点击这里获取资源:https://dev59.com/x3VD5IYBdhLWcg3wXaed - Eliseo Ocampos
GCC有一个“内部”手册,记录了一些特定的内部细节,例如它的机器描述文件以及用于表示函数逻辑、GIMPLE和RTL内部表示的数据结构:https://gcc.gnu.org/onlinedocs/gccint/。但这并不是关于它如何工作的概述。 - Peter Cordes
10个回答

28

从龙书开始学起...(注重代码优化和代码生成)

然后写一个类似Decaf或Cool这样的教育性编程语言的玩具编译器,你可以使用解析器生成器(如lex和yacc)来简化前端的工作(以便更加专注于重要内容)...

最后阅读gcc内部书籍并浏览gcc源代码。


2
谢谢,好序列。我认为“龙书”是:http://en.wikipedia.org/wiki/index.html?curid=188976 - Justicle
2
是的,那就是龙书。我读过第一版。它有一个简单得多的龙... - RBerteig
2
该死。人们一直推荐这个。不是我。先从一个随意的介绍开始——说“让我们建立一个编译器”——然后看看一个带有所有数学和理论的计算机科学参考资料。 - dmckee --- ex-moderator kitten
3
我建议不要试图理解GCC。就编译器而言,它相当不寻常,而且它的架构设计故意被削弱了(也就是说,设计本身就存在缺陷,这不是开玩笑)。请注意,这并非在嘲笑GCC。 - Dietrich Epp
1
当涉及到理解你正在做的事情时,LEX和YACC只是增加了一个额外的技术层,使你对正在发生的事情视而不见。如果目标是理解编译器的工作原理,递归下降解析器将比使用LEX和YACC更好地帮助你理解。一般来说,如果你只是把它作为学习练习,那么在没有别人帮助的情况下,你可能不会在空闲时间写一个优化编译器。 - NoMoreZealots
如果你只对编译器优化感兴趣,那么你可以尝试使用SUIF。 - sourabh jaiswal

11

我正在翻阅GCC内部手册,但它似乎并不适用于“学习”编译器的工作原理。这不是一个教学文档,它假定你已经了解该主题。 - NoMoreZealots

11
编译器文本很好,但对于自学来说有点繁重。Jack Crenshaw有一本名为“让我们构建编译器”的系列文章可以下载阅读。它遵循“边做边学”的方法,非常适合那些在这个领域没有通过正式课程学到东西或者已经多年没有学习了的人(就像我这样)。它会手把手地教你写一个编译器,而不是用Lambda演算和深奥的理论问题来折磨你,这些只有学术界才关心。它是激发那些只有模糊记忆曾经在Vax (没错,就是VAX!)上写过东西的大脑细胞的好方法。它的语言非常流畅易懂,可以轻松阅读,而不像大多数教科书需要喝几壶咖啡才能过第一章。一旦你有了基础的理解,更传统的文本如《龙书》就是拓展你理解的好参考。(我个人比较喜欢纸质版,我打印了Jack的书,这样比在笔记本电脑上看书更容易阅读。而且电子书阅读器对于一些希望感觉读实体书的人来说太贵了。)
有些人可能会认为它的“缺点”是它是用Pascal编写的,但我认为这比如果有人给我一个可用的C程序让我开始思考更能让我深入思考。除此之外,它是以68000为基础编写的,但目前只在嵌入式系统中使用。对我而言也不是问题,因为我懂得68000汇编语言,而且68000汇编语言比其他汇编语言更易读。

9
如果您想要纸质版,请尝试《编译器设计的艺术:理论与实践》。 (购买链接)

4
正如 Pete Eddy 所指出的,Jack Crenshaw 的教程非常适合新手。但是如果你想看看一个真正的、生产级别的 C 编译器是如何工作的——这是由杰出的工程师设计而不是通过将代码丢到墙上直到有东西粘着而创造出来的——那么你需要获得一本 Fraser 和 Hanson 的《可重定向C编译器:设计与实现》,其中包含了非常干净的{{link2:lcc}}编译器的源代码。设计和实现的解释与代码混合在一起。这不是初学者的第一本书,但仔细研究后会收到回报,你可以花35美元买一本二手书。
关于 lcc 的更长介绍,请参见 在 Linux 上快速编译 C。 lcc 网页上也有很多好的教材链接。然而,我不知道有没有我真正喜欢的入门教材。

P.S. 抱歉你在大学被骗了。


谢谢你的建议 - 我会去看看lcc。 - Justicle
优秀的工程师?Jack Crenshaw 设计了航天飞机的部分零件,而自制电脑则是他的业余爱好。并不是要质疑那些编写 lcc 的人的智力,但设计编译器并不需要非常聪明。这真的不难。 - NoMoreZealots
1
参考并非指Crenshaw而是gcc。RMS是许多事情,但卓越的工程师不是其中之一。然后加入1000只猴子,搅拌均匀... - Norman Ramsey


3

2

根据您想了解的具体内容,您应该看一下管道和过滤器模式,因为据我所知,这种模式(或类似的模式)在过去几年中被用于许多编译器。

当我的编译器知识不太过时时,它的工作方式如下:

将源代码解析为符号表示

清理符号表示,进行一些规范化处理

基于某些规则优化符号树

根据符号树编写可执行代码

当然还需要解决依赖关系等问题。

当然,查看gcc或javac源代码可能有助于更详细地了解。


1

阅读编译器的源代码也可能是有价值的。我怀疑GCC不是最好的第一选择,因为它负担着对语言20多年演变的完全兼容性。但我也确信,通过内部参考手册指导的源代码阅读将是有益的。

我认真考虑过查看一个内部编译成虚拟机字节码的脚本语言的源代码。有几种语言符合这个描述,但我会从Lua开始。这种语言很小,虚拟机很新颖。源代码也很小,我看过的部分非常清晰,尽管注释很少。


0

看一下万花筒。 使用LLVM,您可以在短短几天内编写自己的编译器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接