c语言怎么那么难
作者|劉欣
本文经批准转载自旋风分离器翻身
这是我的星球提出的问题。 “c语言本身是用什么语言写的? ”
换个角度看,其实C语言在运行之前必须编译,C语言的编译器来自哪里? 是用什么语言写的? 如果是用c语言本身写的话,是先有蛋还是先有鸡?
假设世界上不存在编译器,我们先从机器语言开始,看看该怎么办。
机器语言可以直接在CPU上执行,不需要编译器。
然后是汇编语言。 汇编语言只是机器语言的助记符,但必须将其编译成机器语言才能运行。 没办法,只能用机器语言写这个第一个编译器。
汇编语言问题解决后,迈出了一大步。 此时,可以用汇编语言编写c语言的编译器。 我说这是c编译器的祖先。
有了这个祖宗,就可以编译任何C语言程序,那可以用C语言本身写编译器吗? 用祖先编译就行了。
ok,有了这么多层,我终于得到了用c语言写的编译器。 真的很辛苦。
此时,用以前的程序集编写的c语言编译器将被丢弃。
当然,如果在c语言之前出现了其他高级语言(如Pascal ),则可以使用Pascal编写c语言的编译器。
据说第一个Pascal的编译器是用Fortran写的。
第一种高级语言Fortran应该是用汇编语言编写的编译器。
关于编译器,这里有一个有趣的传说:
Unix的发明者之一Ken Thompson在贝尔研究所,据说大摇大摆地走到任何一台Unix机器前,输入自己的用户名和密码就可以通过根登录!
贝尔研究所人才济济,其他大牛发誓会找到这个漏洞。 他们通读了Unix的C源代码,终于找到了登录的后门,打扫了后门后编译并运行了Unix,但是Thompson可以登录了。
有人以为可能是编译器出了问题,所以在编译Unix时嵌入了后门。 于是,他们又用c语言重写了编译器,用新的编译器重新编译了Unix。 这样天下终于平静了吧。
尽管如此,Thompson仍然可以通过根登录。 真的崩溃了。
之后,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。
然后C3,C4 .最后得到完整的c语言。
这个过程称为bootstraping,在中文中称为引导。
作者简介:刘欣,畅销书《码农翻身》作者,15年以上开发经验,原IBM架构师,领导多种企业APP架构的设计与开发; 善于洞察技术的本质,用故事说明复杂的技术。
【END】