C 语言这么厉害,它自身是用什么语言写的?

 

 

做者 | 刘欣bootstrap

本文经受权转载自码农翻身(ID:coderising)api

这是来自个人星球的一个提问:“C语言自己用什么语言写的?”架构

换个角度来问,实际上是:C语言在运行以前,得编译才行,那C语言的编译器从哪里来? 用什么语言来写的?若是是用C语言自己来写的,究竟是先有蛋仍是先有鸡?函数

 

 

咱们假设世界上不存在任何编译器,先从机器语言提及,看看怎么办。 网站

机器语言能够直接被CPU执行,不须要编译器。架构设计

而后是汇编语言, 汇编语言虽然只是机器语言的助记符,可是也须要编译成机器语言才能执行,没办法只能用机器语言来写这第一个编译器了(之后就不用了)。 设计

汇编语言的问题解决了,就往前迈进了一大步,这时候就能够用汇编语言去写C语言的编译器,咱们说这是C编译器的老祖宗。 指针

有了这个老祖宗,就能够编译任意的C语言程序了,那是否是能够用C语言自己写一个编译器?只要用老祖宗编译一下就能够了。code

OK,这么一层层上来,终于获得了一个用C语言写的编译器, 真是够麻烦的。 事件

到这个时候,以前那个汇编写的C语言编译器就能够抛弃了。 

固然,若是在C语言以前,已经出现了别的高级语言,例如Pascal,那就能够用Pascal来写一个C语言的编译器。

第一个Pascal的编译器听说使用Fortran写的。而作为第一个高级语言的Fortran,它的编译器应该是汇编语言写的。

 

 

关于编译器,这里边有个有趣的传说:

传说Unix 发明人之一的 Ken Thompson在贝尔实验室,大摇大摆的走到任何一台Unix机器前,输入本身的用户名和密码,就能以root的方式登陆! 

贝尔实验室人才辈出,另一些大牛发誓要把这个漏洞找出来,他们通读了Unix的C源码,终于找到了登陆的后门,清理后门之后编译Unix , 运行,但是Thompson 仍是可以登陆进去。

有人以为多是编译器中有问题,在编译Unix的时候植入了后门,因而他们又用C语言从新写了一个编译器,用新的编译器再次编译了Unix,这下总算天下太平了吧。

但是仍然无论用,Thompson 依然能够用root登陆,真是让人崩溃 !

后来Thompson 本人解开了秘密,是第一个C 语言编译器有问题,这个编译器在编译Unix源码的时候,固然会植入后门,这还不够,更牛的是,若是你用C 语言写了一个新编译器,确定也须要编译成二进制代码啊,用什么来编译,只有用Thompson写的那第一个编译器来编译,好了,你写的这个编译器就会被污染了,你的编译器再去编译Unix , 也会植入后门 :-)

说到这里我就想起了几年前的XcodeGhost 事件,简单来讲就是在Xcode(非官方渠道下载的)中植入了木马,这样XCode编译出的iOS App都被污染了,这些App就能够被黑客利用作非法之事。 

虽然这个XCodeGhost和Thompson的后面相比差得远,可是提醒咱们,下载软件的时候要走正规渠道,从官方网站下载,认准网站的HTTPS标准,甚至能够验证一下checksum。

 

 

可能有人问:我用汇编写一段Hello World都很麻烦,竟然有人能够用它写复杂的编译器?这可能吗?

固然可能,在开发第一代Unix的时候,连C语言都没有,Ken Thompson 和 Dennis Ritchie 但是用汇编一行行把Unix敲出来的。WPS初版是求伯君用汇编写出来的,Turbo Pascal 的编译器也是Anders 用汇编写出来的,大神们的能力不是普通人能想象获得的。 

对于编译器来讲,还能够采用“滚雪球”的方式来开发:

仍是以C语言为例,第一个版本能够先选择C语言的一个子集,例如只支持基本的数据类型,流程控制语句,函数调用...... 咱们把这个子集称为C0。

而后用汇编语言写个编译器,只搞定这个语言的子集C0,这样写起来就容易很多。

C0这个语言能够工做了,而后咱们扩展这个子集,例如添加struct,指针.....把新的语言称为C1。 

那C1这个语言的编译器由谁来写?天然是C0。

等到C1能够工做了,再次扩展语言特性,用C1写编译器,获得C2。 

而后是C三、C4......最后获得完整的C语言。

这个过程被称为bootstraping , 中文叫作自举。

做者简介:刘欣,畅销书《码农翻身》做者,15年以上开发经验,前 IBM 架构师,领导过多个企业应用架构设计和开发工做;洞察技术本质,擅长用故事去讲解复杂技术。