C语言的发展史(The Development of the C Language)
The Development of the C Language*
Dennis M. Ritchie
Bell Labs/Lucent Technologies
Murray Hill, NJ 07974 USA
不满足网上的译文,yqj2065自己翻译一下。备用。【】是译注、补充。
概要
在1970s早期,C编程语言是作为新生的Unix操作系统的系统实现语言而设计的。衍生于无类型(typeless)语言BCPL,它进化出了一个类型结构【类型系统】;在弱小的机器上,作为改善简陋编程环境工具的这一创新,它已然成为当今主流语言之一。本文研究它的进化。
NOTE: *Copyright 1993 Association for Computing Machinery, Inc. This electronic reprint made available by the author as a courtesy. For further publication rights contact ACM or the author. This article was presented at Second History of Programming Languages conference, Cambridge, Mass., April, 1993.
It was then collected in the conference proceedings: History of Programming Languages-II ed. Thomas J. Bergin, Jr. and Richard G. Gibson, Jr. ACM Press (New York) and Addison-Wesley (Reading, Mass), 1996; ISBN 0-201-89502-1.
简介
本文讲述C程序设计语言的发展、它所受到的影响以及它诞生的条件。简洁起见,我省略了对C自身、它的父亲B[Johnson 73]和祖父BCPL[Richards 79]的完整描述,而是关注每一种语言的特性要素和它们如何演化。
在1969-1973年间,C的出现,伴随着Unix操作系统早期的发展,最富创造性的时期是1972年。另一个一连串改变的高峰期是1977到1979年间,此时Unix系统的可移植性得以证实。第二个阶段期间,出现了第一份被广为传播的该语言的描述:The C Programming Language,通常被称为‘易做图’或K&R[Kernighan 78]。最后,在1980年代中期,该语言被ANSI X3J11委员会正式标准化,并作出进一步修改。截止1980年代早期,尽管已有各种机器结构及操作系统的【C的各种】编译器,该语言几乎与Unix特别密切关联;更近一些,它的使用传播得更广,而今天它是整个计算机产业中最广泛使用的语言之一。
历史背景
1960s晚期,是Bell Telephone Laboratories(贝尔电话实验室)的计算机系统研究(中心)的动荡岁月[Ritchie 78] [Ritchie 84]。计算机被从Multics项目组拖走[Organick 78],该项目是MIT(麻省理工学院)、General Electric(通用电气公司)和贝尔实验室的合作项目。到1969年,贝尔实验室管理层、甚至研究人员认为,Multics项目不能按期完成并且代价高昂。甚至在GE-645 Multics机器被撤走之前,早期由Ken Thompson领导的一个非正式小组,已经着手一些其它的研究。
Thompson希望按照自己的设计、使用可用的任何方式,创造一个舒适的计算环境。事后诸葛亮地说,他的计划集成了Multics的许多创新方面,包括关于进程的清晰概念——控制块,树型结构的文件系统、作为用户级程序的命令解释器、文本文件的简单表示和访问设备的通用化。他们排除了其余特性,比如对内存和文件的统一访问。此外,
开始的时候,他与我们这些俗人遵循[推迟?]Multics的另一个先驱性(虽然不是原创)特性,即几乎仅用高级语言来编程。PL/I【Programming Language One,IBM公司在1950s发明的高级编程语言】——Multics的实现语言不太符合我们的口味,因而我们也使用其他语言,包括BCPL,我们担心【regretted?】失去使用在汇编程序的级别以上的语言进行编程的优势,即容易编写、易于理解。当时我们并未特别关注可移植性,到后来才有了这方面的兴趣。
Thompson面临的硬件环境,即使在那个时代也是又拥挤又简陋:他从1968年就开始使用的DEC PDP-7,只有8K的18bit字(长)的内存,并且没有对他有用的软件。虽然心想着使用高级语言,他还是用PDP-7汇编器编写了最初的Unix系统。刚开始的时候,他甚至并未在PDP-7上编程,而是在一台GE-635机器上使用GEMAP汇编器的一些宏。一个后处理器(postprocessor)生成PDP-7可读的纸带。
这些纸带从GE机器拿到PDP-7上进行测试,直到一个原始的Unix内核(kernel)、一个编辑器、汇编器、一个简单的外壳(shell)(命令解释器)和一些工具(像Unix rm, cat, cp命令)被完成。此后,这个操作系统可以自我支持:可以编写和测试程序,勿需借助纸带,并且程序开发可以在PDP-7上持续进行。
Thompson的PDP-7汇编器在简明性上甚至优于DEC的;它对表达式求值并得到对应的比特流【二进制源代码】。没有库、没有装载器或没有链接器:程序的全部源文件提交给汇编器,而其输出文件(the output file)——有一个固定名字——是可以直接执行的(这个名字,a.out,道出了一点Unix渊源;它是汇编器的输出。甚至在系统有了链接器和有了显式指定另一个名字的方式之后,它仍被保留作为编译器的默认可执行文件(名))。
Unix在PDP-7上首次运行后不久,1969年Doug McIlroy创造了这一新系统的第一个高级语言:一个McClure的TMG实现[McClure 65]。TMG是一种自顶而下,递归降解(top-down, recursive-descent)风格的编写编译器(更一般地,TransMoGrifiers)的语言,它将上下文无关的语法表示法与过程(式程序)元素相结合。McIlroy和Bob Morris使用TMG为Multics编写了早期的PL/I编译器。
受McIlroy重造TMG事迹的易做图,Thmopson认为Unix(当时可能还没有取这个名字)需要一种系统编程语言。经过用Fortran的短暂而受阻的尝试后,他创造了一门他自己的语言,他称之为B。B可被视为没有类型的C。更准确地,它是塞进8K字节内存,经过Thompson大脑过滤后的BCPL。它的名字最有可能表示为BCPL的缩写,尽管另一种理论认为它源自于Bon[Thompson 69],Thompson在Multics的那些日子创造的一门不相关的语言。Bon进而二中其一,可能是以他妻子Bonnie的名字,或者(根据它的操作手册中的一个百科全书般的引用)以一种宗教命名,该教仪式涉及咕隆咕隆的神奇咒语。【不知道是不是易做图的原始宗教:苯教(Bon)】【太难搞了】
起源:这些语言
BCPL是由Martin Richards于1960年代中期,在访问麻省理工学院时设计,在1970年代早期被用在几个有趣的项目中,其中包括位于牛津的OS6操作系统[Stoy 72],和施乐公司PARC研究中心的创造性项目Alto的一部分[Thacker 79]。我们熟悉该语言,是因为Richards工作过的MIT CTSS系统[Corbato 62]被用于Multics开发。最初的BCPL编译器被Rudd Canaday和贝尔实验室的一些人们移植到Multics和GE-635 GECOS系统上[Canaday 69];在贝尔实验室的Multics项目奄奄一息阶段,它成为随后转入Unix的一帮人选择的语言。
BCPL、B和C都归属于以Fortran和Algol 60为代表的传统过程式家族。它们格外地倾向面向系统编程、小巧、描述简洁,而且可被简单的编译器轻易地翻译。它们接近机器,它们所引入的抽象以传统计算机所提供的具体数据类型和操作为基础,它们依赖于例程库以输入输出以及与操作系统的其它交互。尽管不太成功,它们还使用库程序指定其他有趣的控制结构,如协程和过程关闭。同时,它们的抽象层次足够高,足够用心的话,能达到机器间的可移植性。
BCPL, B和C在很多细节上存在语法差异,但总体上它们是相似的。程序由一系列的全局声明和函数(过程)声明组成。BCPL中,过程能够嵌套,但不能引用定义在外包过程中的非静态对象。B和C通过更强行的限制避免了它:基本就没有嵌套过程。每一种语言(除了早期的B版本)都认可(文件的)分别编译,并提供了从指定文件中包含(including)文本的方式。
BCPL中的若干语法和词法机制较B和C中的更优雅和正式的。例如,BCPL的过程和数据声明拥有更一致的结构,并且它提供了一套更完整的循环结构。尽管BCPL程序名义上是由分界的字符流构成,聪明的规则使得以每一行结束的语句可以省略其分号。B和C忽视了这种便利,大多数语句以分号来结束。刨除这些差异,BCPL的大多数语句和操作符直接对应B和C中的相应物。
BCPL和B之间的一些结构化的差异源于介质存储的限制。比如,BCPL声明采用这样的形式
let P1 be command
and P2 be command
and P3 be command
...
此处的由命令表示的程序文本包含完整过程。这些子声明相互关联而且同时出现,所以名字P3在过程P1内可见。相似地,BCPL能在求得一个值的表达式里包含一组声明和语句,例如
E1 := valof ( declarations ; commands ; resultis E2 ) + 1
BCPL编译器在产生输出前,通过存储和分析内存中该完整程序的解析过的表示,可以容易地处理此类构造。B编译器所受的存储限制决定了一种一次通过( one-pass)技术,由此尽可能快生成输出,而这一语法上的重新设计将这种可能带入到C。
BCPL中一些不令人满意的地方归因于它的技术问题,在B的设计中它们被有意识的避免了。例如,BCPL使用一个“全局向量”(global vector)机制以在分离编译的程序间通信。在这种模式中,程序员使用一个全局向量的数值偏移量,显式关联每个外部可见过程和数据对象的名字。链接使用这些数值偏移量,在被编译过的代码上完成。B起初坚持,整个程序一次性全部传递给编译器,来规避这个麻烦。B的后期实现,和C的全部实现,使用一个传统的链接器,来解决出现在分离编译文件中的外部名字,而不是把指定偏移量的负担推给程序员。
BCPL到B的转换中引入的其它变化,大概是因为风格的缘故,一些仍是有争议的,例如赋值使用单个字符=代替:=。类似地,B使用/**/来括起注释,而B使用//注释直至行末的文本。这显然是从PL/I继承来的。(C++重新启用了BCPL的注释惯例。) Fortran影响了声明的语法:B的声明以一个auto, stat
补充:软件开发 , C语言 ,