c语言编译器 知乎

在2013年上本科时候,刚开始学c语言时,程序编译运行。就很神奇,编译过程中,编译器怎么就知道成千上万行代码中哪句代码有问题,能定位到某一行某一列,甚至还能提示你如何修改代码,这是如何做到的呢,也太奇妙了吧!!!尽管有这样的疑惑,

在2013年上本科时候,刚开始学c语言时,程序编译运行。就很神奇,编译过程中,编译器怎么就知道成千上万行代码中哪句代码有问题,能定位到某一行某一列,甚至还能提示你如何修改代码,这是如何做到的呢,也太奇妙了吧!!!尽管有这样的疑惑,但是当时的我实在太菜,也不是计算机专业,于是也没有深究。但是这个疑惑和好奇一直伴随着我。

后面读了计算机研究生,决定解开这个迷惑,寒假期间,于是按照网上推荐,买了经典的编译原理龙书,虎书等等多本书,看了感觉还是很高深,于是去B站看了哈工大老师的编译原理视频,感觉自己好像懂了,但是好像又什么都没懂,仍然没有解开我一直以来的疑惑,也没有获得编译技术感性的认识,由于学习和科研事情较多,就又搁置一边了。

最近一个月前,随着自己对C语言的熟练使用和操作系统内核的开发,以及想做一个好用的C语言IDE(具备代码智能提示,语法错误动态检测等基本功能),再次点燃了我对编译器的执念,曾经的疑惑和好奇心一直涌在心头,加上之前已经掌握的编译原理的一些基础知识(不久前也买了本自己动手实现编译器链接器认真看了,一本自己动手实现lua虚拟机编译器也大概看了),我决定了,这一次,我一定要彻底解决我这个一直以来的疑惑。

1. 学习哪个C编译器源码?

从理解规律来说,“应该是先感性认识,再理性认识,再到感性认识”,是最好的学习方式。因为我有了研究生阶段对于编译原理的一些基础,而且我也有着很多的c语言程序开发经验,因此,我现在缺乏的是C编译器的源码直接学习了。纸上得来终觉浅,绝知此事要躬行。

因此要找一个适合学习的编译器才行,因此,网上又搜索适合学习开源编译器源码,仍然找到推荐的大量各种各样C语言编译器的答案。

这里我做了个总结:我觉得比较好的学习原则如下:

  • 编译器源代码本身也是用C语言写的(因为我对C语言熟悉)
  • 源码大概在2w行以内(因为一般而言一个人能学习掌握的开源代码1w行左右)
  • 源码结构清晰,命名规范(不要太缩写,且见名知意,最好是驼峰命名,因为匈牙利命名法,实在觉得下划线和减号-辨识度不好,而且标识符冗长)
  • 代码注释非常丰富,因为这样才容易理解
  • 有配套的书籍,因为配套的书籍会非常严谨和详细的描述里面的实现细节,对于理解代码最为奏效

网上搜索后,有如下一些好的答案:
GitHub 上有没有什么简单精致的编译器源码适合初学者研读?? - 知乎

想学一下编译原理,有什么书籍推荐吗? - 知乎

学编译原理有什么好书? - 知乎

推荐比较多的 

  • TCC:全称tiny CC,说是短小精悍,而且还可以不需要编译,直接执行C语言,也就是可以把c语言直接当脚本执行,但是没有详细的学习资料
  • LCC:代码不清晰
  • GCC:代码量太多,没法学
  • LLVM:代码量太多,没法学
  • UCC: UCC, your C Compiler!

上述都是完整版C语言的编译器,还推荐了很多其它的开源学习编译器,但是都是 一个C语言子集的编译器(比如不支持浮点数,如我看的书自己动手实现编译器和链接器做的SC语言,又比如c4编译器等),或者其它编程语言的(lua,luna,javac),很多的就是个玩具语言,玩具编译器罢了,不适合真刀真枪的学。说实话,有些开源项目再好,如果没有好的配套资料和教材,那也不适合自己学习。还有一点就算,网友还推荐了一些开源编译器,虽然代码量只有几千行,功能也很完整,但是还是没有详细资料啊!!!

总结来看,最后选了UCC,代码1.5w行,代码质量高,网上有csdn系列博客(C编译器剖析_前言_SheIsC的博客-CSDN博客_c编译器剖析 pdf),有pdf可以下载,还能买到邹昌伟的一本书(C编译器剖析,而且里面写的前言,真的引起了强烈的共鸣,一种这就是原来这就是我一直想找的一本书的感觉),非常适合学习。而且功能性各方面,编译报错,和gcc,clang它们对标的,太棒了。

其它相关参考文章:

C语言开源项目 - 简书

给开源编译器插入后门 | Bojie Li(这个很有意思,也就如果官方的发行版(官方自己编译好的exe)如果都有问题,那么就能留后门而不会被发现了,所以这个问题我觉得确实存在。因此工具链必须完全自主发展,才能完全避免)

2. 如何学习?

既然确立了学习对象,那么就是认真学了。

  • 不要浮躁,要静下心来跟着教程学习,因为这是至少15天以上的全身心投入学习才能学明白的,因为编译器源码是所有其它源码(比如RTOS内核源码等)中最难的
  • 针对每一个函数,先自己分析能看懂不(相当于预习),看不懂再自己跟着教程对这个函数的讲解,学明白,而且把自己的思考都记录为代码注释
  • 用vscode或者sourceinsight等代码阅读软件,同时在纸上自己画示意图,推敲
  • 最后要运行实践,才能更加明白,否则容易忘记

3. UCC学习总结

UCC没有预处理器(比如宏展开,头文件插入等),只能处理别的预处理器先处理过的文件。

  1. UCC进行语法分析(词法分析包含在了里面顺便进行,就是GetNextToken()函数),生成一颗语法树(由多个结构体链起来,每个结构体描述一个信息集合,符号的类型初步形成),检查是否符合C89标准文法,其实就是递归下降逐步匹配的过程
  2. 语义检查,会对语法树进行语义检查(按照c标准语义规定文档,逐个节点检查,同时完善每个符号的类型)。比如2=3,语法检查能通过,但是语义检查会报错,因为常量不能赋值(语义文档规定的)。这棵树最多两个孩子,因为每个运算符最多只有两个操作对象,另外,有多的结构的情况,会被归为另一个结构体情况(变成另一个支树),因此总是只有两个孩子。
  3. 中间代码生成,就是把现在的语法树转为中间代码(t0=a+b;t1=t0+c等),这是很接近汇编指令的一种中间代码了,产生了大量的临时变量(因为c语言的三个数连加,而汇编只能两两相加,因此中间代码就是很多的这种两两表达式,是为了便于汇编指令生成),然后就可以做很多的优化空间(这也是提供编译器性能的地方,是学术研究热点,编译出更少的指令和优化不必要的执行,意味着目标指令更少,执行速度也能更快)
  4. 中间代码翻译成3地址码,这是统一表示为运算符,目标操作数,操作数1,2,3的指令形式,还是一种中间指令,但是这个指令已经非常接近汇编指令了
  5. 将3地址码逐条翻译为汇编指令吗,这个是利用模板替换的方式(翻译到x86 linux平台,就用对应的汇编指令模板,其它平台也是同样的),因为很多指令是套路的,比如函数进入和退出,每个函数其实都是那些固定指令

UCC只能得到每个c文件的汇编文件,还需要传递给其它的工具链,链接器,汇编器等,最后才能成为一个可运行的二进制文件。

4. 感悟

看完了UCC编译器源码,很有难度,但是收获很多,没有半个月的全身心投入,认认真真,静下心一点点看,是很难看明白的。其中的一个感觉就是,对于外行或者一般的内行,就算能掌握一个东西的基本原理和具体实现,也只能做到平庸水平。比如编译器,不是把教材上的原理看懂了,也拿了个实际开源编译器源码都掌握了,也能开发出这样一个编译器,就叫做牛逼了,这个只能叫做一般水平。编译器里面的代码优化这些是提高性能的核心,需要深入的研究,做出的编译器才能是先进的产品,否则就是个玩具而已,或者平庸的产品。

我的学习过程中的一些记录:

UCC编译器学习笔记1_标biao的博客-CSDN博客

UCC编译器学习笔记2_标biao的博客-CSDN博客

UCC编译器学习笔记3_标biao的博客-CSDN博客

UCC编译器学习笔记4_标biao的博客-CSDN博客

UCC编译器学习笔记5_标biao的博客-CSDN博客

UCC编译器学习笔记6_标biao的博客-CSDN博客

UCC编译器学习笔记7_标biao的博客-CSDN博客

UCC编译器学习笔记8_标biao的博客-CSDN博客

UCC编译器学习笔记9_标biao的博客-CSDN博客

UCC编译器学习笔记10_标biao的博客-CSDN博客

UCC编译器学习笔记11_标biao的博客-CSDN博客

UCC编译器学习笔记12_标biao的博客-CSDN博客

UCC编译器学习笔记13_标biao的博客-CSDN博客

UCC编译器学习笔记14_标biao的博客-CSDN博客

UCC编译器学习笔记15_标biao的博客-CSDN博客

UCC编译器学习笔记16_标biao的博客-CSDN博客

UCC编译器学习笔记17_标biao的博客-CSDN博客

UCC编译器学习笔记18_标biao的博客-CSDN博客

UCC编译器学习笔记19_标biao的博客-CSDN博客

UCC编译器学习笔记20_标biao的博客-CSDN博客

UCC编译器学习笔记21_标biao的博客-CSDN博客

知秋君
上一篇 2024-08-02 11:36
下一篇 2024-08-02 11:02

相关推荐