C语言的发展史-3

C语言的发展史1   

C语言的发展史-2

原文 The Development of the C Language

不满足网上的译文,yqj2065自己翻译一下。备用。【】是译注、补充。


C初生

    在本语言取名后,快速地变更不停,例如&&和||操作符的引入。在BCPL和B中,表达式求值依赖于上下文:在if和其它条件语句中比较一个表达式的值与零,这些语言对与(&)和或(|)运算符给与了特别的解释。在普通上下文中,它们按位运算,而在这个B语句中
    if (e1 & e2) ...
编译器必须对e1求值而且如果值为非零值,对e2求值,而且如果它也非零,则执行依赖if的语句。对于e1和e2内部的&和|操作符要求递归地计算。在这种true-值环境中的布尔运算符的短路(short-circuit)语义似乎令人满意,但是运算符的重载难以解释和运用。在Alan Snyder的建议下,我引入了&&和||运算符,使这种机制更明了。
它们迟到地引入解释了C优先级规则上的一个不幸。B中某人编写
    if (a==b & c) ...
来检测a和b是否相等并且c是否非零;在这样的条件表达式中,&比==的优先级低比较好。在从B转变为C时,某人希望在这种表达式中用&&代替&;为了使这种转换不那么痛苦,我们决定保持运算符&与==有相等的优先级,而仅仅把&&的优先级与&的做了细微区分。今天看来,变动&和==的相对优先级会更好,这样就能简化一个C通用的惯用法:为了测试一个掩码值和另一个值,人们必须这样写
    if ((a&mask) == b) ...
那个内层的圆括弧是需要的,但容易被忘记。
    许多其它改变发生在1972-73年,但最重要的是引入了预处理器,部分原因是Alan Snyder[Snyder 74]的建议,也(因为)沿用在BCPL和PL/I中已存在的文件包含机制。它的原始版本极之简单,仅提供文件包含和简单字符串替换:#include和参数化宏#define。之后很快对它进行了扩展,合并了宏与参数还有条件编译。之后不久,它被扩展为带参数宏和条件编译,主要是Mike Lesk的工作,后来是John Reiser。预处理原本是作为语言本身的一个可选附件。许多年来,除了源代码在开始处包含一些特别符号外,它们不被使用。这种看法持续至今,也解释了在早期参考手册中,预处理语法与语言其它部分描述不完整,和对它的不精确描述。

可移植性

到1973年早期,现代C的基础部分已经完成。在那年夏天,该语言和编译器已足够强大,以允许我们用C为PDP-11重写Unix内核。(在1972年,Thompson已经简短尝试用C的早期版本——结构体之前,生成系统代码,但放弃了那次努力)也是在这段时期,编译器被转向了其它附近的机器,特别是Honeywell 635和IBM 360/370;因为语言不能独自存在,现代库的原型被开发。特别是Lesk写了一个“可移植I/O包”[Lesk 72],后来被修改成为C的“标准I/O”例程。在1978年,Brian Kernighan和我出版了 The C Programming Language(C程序设计语言)[Kernighan 78]。尽管这本书没有描述一些后来变成通用的附属项,该书充当语言标准达十多年,直到一个正式的标准被采纳。尽管我们在本书上密切共事,但是分工明确:Kernighan编写了几乎所有的说明内容,而我负责包含参考内容的附录,和Unix系统的接口的那一章。

在1973-1980年间,语言又有了一些发展:类型结构增加了unsigned, long, union和枚举类型,并且结构体几乎成为第一类对象(仅缺少一个字面值符号)。同样重要的发展出现在它的环境和其它伴随技术上。用C编写Unix内核使我们对该语言的有用性、效率有足够的信心,去重写系统的库和工具,并且随后把其中最有趣的东西移到其它平台。像在[Johnson 78a]中描述的那样,我们发现传播Unix工具的最困难的问题,并不是C语言和新硬件的接口,而在于适应其它操作系统上的现有软件。因此Steve Johnson开始了pcc——一个C编译器的工作,目的是容易移植到新机器上[Johnson 78b],在他,Thompson和我开始把Unix系统移到Interdata 8/32计算机的时候。

在这时期,语言的变化——特别是1977年左右,主要集中在可移植性和类型安全的考虑上,努力处理在移植大量的代码到新的Interdate平台时我们预见和观察到的问题。那时的C依旧强烈地呈现出无类型根源的特征。例如在早期语言手册或存在的代码中,指针与整型内存索引几乎没有区别;字符指针和无符号整数的算术特性的相似性,使得很难抵御将它们看成同一个东西的诱惑。添加unsigned类型使得无符号算术能够不混淆于指针运算。类似地,早期语言容忍整数与指针间的赋值,但这种作法开始变得不受鼓励;一个类型转换符号(在Algol 68的例子中被称作“casts”)被发明,以更明显指示类型转换。受PL/I例子的诱惑,早期C没有将结构体指针强烈绑定到它们所指向的结构体,而是允许程序员用pointer->member但几乎不用考虑指针的类型;这样的表达式不经大脑地用作被指针指派的内存区域的引用,而成员名字仅表示一个偏移量和类型。

尽管K&R第一版描述了把C的类型结构用于其呈现形式的大部分规则,许多程序的编写(使用了)遗留的旧式、更松散风格,而且编译器还得容忍它们。为了鼓励人们更加关注于正式的语言规则、检测合法但可疑的写法、并帮助发现分离编译中简单机制难以检测的接口的错误匹配,Steve Johnson修改其pcc而产生了lint[Johnson 79b],用于扫描一系列文件并标记可疑的写法。

在使用中成长

我们在Interdata 8/32的可移植性试验的成功,很快导致了Tom London和John Reiser在DEC VAX 11/780上的另一次成功。这种机器比Interdata变得更流行,并且Unix和C语言开始在AT&T公司内部和外面快速传播。尽管到1970年代中期,Unix已经被用于各种项目,包括贝尔系统的,以及我们公司外的一小群以研究为目的的机构、学院和政府机构,它的真正成长开始于达到可移植性之后。值得特别记住的是刚出现的、基于公司开发和研究团队的AT&T的计算机系统部门(推出的)System III和System V版本系统,和加州大学伯克利分校继承自Bell实验室研究组的BSD系列。
在1980年代,C语言的使用广泛传播,并且几乎每一种机器体系结构和操作系统都有编译器;特别是它变成一种个人计算机上流行的编程工具,包括对这些机器的商业软件制造商和对编程有兴趣的终端用户。在那十年开始时,几乎每一种编译器都是基于Johnson的pcc;直到1985年,才有了许多独立开发的编译器产品。

标准化

到1982年,很明显,C需要正式的标准化。最近似于标准的K&R第一版,不再反应实际使用中的语言;尤其是它没有提及void和enum类型。虽然它预见了(构成)结构体的新方式,只是该书发表后语言才支持对其赋值、将其传递给函数和从函数返回它、以及将成员名字与包含它们的结构体或union严格关联。尽管AT&T发布的编译器包含了这些变化,尽管非基于pcc的编译器的大多数供应商很快添加了它们,但仍没有一个完整、权威的语言描述。

K&R第一版在很多语言细节上也不够精确,而且对于pcc这个“参照编译器”来说,K&R日益显得不切实际;pcc甚至也没有忠实的体现被K&R描述的语言,更别说后续的扩展。最后,开始将C用于商业和政府合同项目意味着批准一个正式标准很重要。因此(在M. D. McIlroy的催促下),在1983年夏天,ANSI建立了接受CBEMA的指导的X3J11委员会,目标是制订一个C标准。X3J11在1989年末提出了一个他们的报告[ANSI 89],后来这个标准被ISO接受为ISO/IEC 9899-1990。

从最开始,X3J11委员会在语言扩展上采取了谨慎、保守的态度。我极其满意,他们严肃地对待他们的目标:“为C程序设计语言制订一个清晰、一致和无二义性的标准,规范C的通用、现行的定义,促进不同C语言环境下的用户程序的可移植性。”[ANSI 89] 委员会意识到,仅仅靠发布一个标准并不会改变这个世界。

X3J11仅给语言本身引入了一个但真正重要的改变:它使用从C++[Stroustrup 86]借鉴的语法,把形式参数的类型添加到函数的类型签名中。用以前的风格,外部函数是这样声明的:
    double sin();
仅说明sin是一个函数,返回一个double(即双精度的浮点数)值。在新的风格中,这个更好的声明
    double sin(double);
使参数类型明显因而鼓励更好的类型检查和适当的转换。即使这个添加,尽管它产生了明显更好的语言,也引起了困难。委员会有理由认为,虽然新风格更好,简单地取缔旧式风格的函数定义和声明不合适。这种必然的妥协自然产生了,尽管允许两种形式使语言复杂化,并且可移植软件的作者必须应付不符合标准的编译器。

X3J11也引入了一大堆较小的附加和修改,例如,类型限定词const和volatile,和稍有不同的类型提升规则。尽管如此,标准化过程没有改变语言的特征。特别是,该C标准没有试图正规化定义语言语义,因而在一些小细节上还可能存在争议;然而,它很好地说明了自最初描述以来(该语言)在使用中的改变,并且对于基于它的实现而言是足够精确的。

因此,C语言核心在标准化过程中几乎毫发无伤,并且该标准更多地表现为一个更好的、周到的法典而非一次新发明。许多重要的改变发生在语言的环境中:预处理器和库。预处理器处理宏替换,使用一些约定以区别于语言的其余部分,它与编译器的交互从未被很好描述,X3J11企图纠正这种情形。其结果明显好于K&R第一版中的解释;除了更全面,它提供了一些操作,如标记的串接,以前只能够在少数实现中可用。

X3J11非常正确地认识到一个完整和仔细的标准C库(standard C library)的描述与它所服务的语言本身(的描述)同等的重要。C语言本身没有提供输入-输出或任何其它与外界交互(的方式),而依赖于一套标准过程。出版K&R的时候,C基本上被视为Unix的系统编程语言;尽管我们提供了库例程例子,该库例程的目标是容易转换到其它操作系统,但来自Unix的底层支持却是默认的。因此,X3J11委员会花了大量时间来设计和归档了一套库例程,它们必须在所有符合标准的实现中可用。

按照标准过程的规则,X3J11委员会的当前活动限定于发布对已有标准的解释。然而,最初由Rex Jaeschke召集的叫NCEG(C数值扩展小组)的一个非正式组织,被正式接受为分组X3J11.1而且他们继续考虑对C的扩展。正如这个名字暗示的,许多可能的扩展打算使该语言更合适于数值的使用:例如,边界被动态检测的多维数组,加入处理IEEE算术的工具,以及使语言在具有向量或其它高级结构特征的机器上更有效。并非所有这些可能的扩展都是数值相关的;也包括一个结构字面值的符号。

继承者

C,甚至B,有一些直接的后代,尽管它们比不过Pascal的繁殖能力。有一个分支发展得很早。当1972年Steve Johnson在休假期间访问滑铁卢大学(University of Waterloo,加拿大)时,他携带了B。它在那儿的Honeywell机器上变得流行,而且产下了Eh和Zed(对“B之后是什么?”的加拿大答案)。当Johnson在1973年返回贝尔实验室时,他莫名其妙地发现,他带到加拿大的种子,该语言已经发展回到(自己的)老巢;甚至他自己的yacc程序已经由Alan Snyder用C重写了。

C的更新的后代可能包括Concurrent C(并发C) [Gehani 89]、Objective C [Cox 86]、C* [Thinking 90],尤其是C++ [Stroustrup 86]。本语言也被广泛用作各种编译器的中间表示(基本上,用作可移植汇编语言),既用于如C++这样的直接后代,也用于Modula 3[Nelson 91]和Eiffel[Meyer 88]的这样的无关的语言。

批评

对比同类语言,最具C语言特色的两个思想是:数组和指针的关系,和声明语法以何种方式模拟表达式语法。它们也是最频繁受到抨击的特性之一,也常常成为初学者的绊脚石。对此两者,历史因素和错误加剧了它们的困难。最为重要的原因是C编译器对类型上的错误的容忍。从上述历史应该清楚,C由无类型语言进化而来。它不是作为拥有自己规则的全新的语言突然出现在其最初的用户和开发者面前;实际上,在语言发展中,我们不得不不断地改编已有的程序,并且要照顾已有代码。(后来,ANSI X3J11委员会在标准化C时面临同样的问题。)

1977年甚至之后的编译器,没有对一些用法给出警告:在整数和指针间的赋值、使用错误类型的对象来引用结构体的成员。尽管在K&R第一版中给出的语言定义,在类型规则的处理上是相当(尽管不完全)自洽,但那本书允许现有的编译器不实施这些规则。此外,某些规则用于简化早期的转换而导致后期的混乱。例如,函数声明中的空方括号
 int f(a) int a[]; { ... }
就是一个活化石,是声明指针的NB方式的遗迹;在C中,a仅在这个特殊的情况下才被被解释为一个指针。该表示法之所以残留,部分源于兼容性,部分是屈从这样的理论——它允许程序员告诉其读者这一意图,传递给f的指针产生于数组而不是引用简单的整型。不幸地是,它对学习者的迷惑与对读者的提示一样多。
在K&R C中,为函数调用提供正确类型的参数是程序员的责任,而已有的编译器不检查类型一致性。原始语言在函数的类型签名中缺少参数类型,是一个重大缺陷,确实是一个需要X3J11委员会以最果敢和最痛苦的精神去修复(的玩意)。早期的设计说明(如果不是证明)了我对技术问题的逃避——特别是分离编译的源文件之间的交叉检查,和我对从无类型到类型语言迁移的含义的不透彻地把握。lint程序,前面提及过,尝试缓解这个问题:作为lint的功能之一,通过扫描一系列源文件、比较调用时和定义时的函数参数类型,lint检查整个程序的一致性和完备性。这种用于表达式的风格沿用于声明语句,所以这些名字可以声明为
    int *fp();
    int (*pf)();
在更为装逼但仍现实的例子中,事情变得更糟糕:
    int *(*pfp)();
是一个函数的指针,函数的返回值是一个整型指针(a pointer to a function returning a pointer to an integer)。有两个因素在起作用。最重要的(因素),C有相对丰富的方式(比如说,跟Pascal比较)进行类型描述。在和C一样的表达型——如Algol 68——语言中,声明语句描述对象同样难以理解,仅仅因为对象它们本身很复杂。第二个作用归因于语法细节。C的声明应该用一个"从内到外(inside-out)"的风格来阅读,该风格被很多人认为难以掌握[Anderson 80]。Sethi[Sethi 81]发现,许多嵌套的声明和表达式会较为简明,如果间接【indirection ,即*】运算符被当作后缀而非前缀时,但是到了(他指出的)那时,再做改变已经太晚了。【君生我未生,我生君已老 君恨我生迟,我恨君生早】[我生君未生,君生我已老。我离君天涯,君隔我海角]

尽管它有些困难,我认为C的声明方式仍然是合理的,我也对此满意;这是一个有用的一致性原则。

C的另一个特征,对数组的处理,尽管它确实很棒但是从实践的角度看,它【较第一点】更令人疑惑。虽然指针和数组间的关系不是通常(形式),(程序员)还是能学会的。而且,该语言在描述一些重要概念方面显示了强大能力,例如,仅仅使用几个基本规则和惯例,(描述了)在运行时长度可变的向量。特别是将字符串按照所有其他数组相同的机制处理,加上一个约定——空字符结束一个字符串。将C的方式与两个同时期的语言Algol68和Pascal[Jensen 74]比较,会很有趣。Algol 68中数组要么有固定边界,要么是“柔性的(flexible)”:对于语言定义和编译器都需要复杂的机制(支持)以适应柔性数组(而且并非所有编译器都完全实现了它们)。原始的Pascal只有固定尺寸的数组和串,这已被证明是有局限的[Kernighan 81]。后来它被部分修复(this was partially fixed),但是最终的语言没有广泛运用。

C把串视为字符的数组,并约定以一个标记结束。除了用字符串文字进行初始化有一个特殊规则,字符串的语义完全包含在管理所有数组的一般性规则中,因此该语言比起其他将字符串当作独立数据类型的语言来,更易于描述和翻译。这一方式会增加一下成本:某些字符串操作比在其它设计中开销更大,因为应用代码或库例程必须时不时地查找串尾、因为没有可用的内置运算,也因为字符串的存储管理的责任压在了用户肩上。不管怎么说,C的操作符方式工作良好。

另一方面,C对数组的处理,总体上(不仅仅是字符串)对优化和未来的扩展有不幸的影响。C程序中指针的盛行,不论是显式声明的还是由数组产生的,意味着优化必须很小心,而且必须谨慎地使用数据流技巧以达到满意的结果。高端的编译器能够懂得大多数可能改变的指针,但是一些重要的用法依然难以分析。例如以产生于数组的指针为参数的函数很难编译生成向量机上有效的代码,因为几乎不可能检测另一个参数指针与另一个参数是否有重迭的数据,或者外部可访问。更重要的是,C的定义非常明确地描述了数组的语义,因而将数组作为更原始对象处理、允许将它们作为整体来操作[这样的]改变和扩展,很难适合现在的语言。甚至声明和使用尺寸动态确定的多维数组的扩展,也曲折难行[MacDonald 89] [Ritchie 90],虽然它们能够使得用C编写数值例程库[变得]更为容易。因而,C通过一个一致而简单的机制,覆盖了实践中需要的字符串和数组的最重要的用法,但是将高效率实现和扩展的问题留了下来
除了上面讨论的,当然,语言及其描述中还存在许多较小的瑕疵。也有一些不纠缠于细节的一般性批评被提出。主要是语言和它要求的基本环境基本上没有为编写大型系统提供帮助。命名结构仅提供了两个主要的级别:“external”(到处可见)和“internal”(在单个过程内)。可见性的一个中间级别(在单个文件内的数据和过程)与语言定义关系很微弱。因而,没有对模块化的直接支持,项目设计师将不得不使用自己的约定。
类似,C本身两种存储生命期:“automatic”对象,当控制流程存在或低于过程时存在,“static”存在于程序的全部执行期。Off-stack,动态分配存储由一个库例程提供,而管理它们的责任落在程序员身上:C对自动垃圾回收不感冒

成功原因?

C的成功远远超出了早期的任何预期。哪些品质促进它得到广泛使用呢?
毫无疑问,Unix本身的成功无疑是最重要的因素;它让这个语言可以被成千上万的人使用。另一方面,C在Unix中的使用,和它的到品种繁多的机器上的可移植性,对[Unix]系统的成功非常重要。而语言对其他环境的侵占揭示了更重要的价值。
尽管对初学者甚至偶尔对老手而言,某些方面很难解,C不失为一个简单和小巧的语言,可被简单和小的编译器翻译。它的类型和操作充分依据真实机器所提供[的对应物],人们用它理解机器如何工作,学会编写时间和空间高效的程序也不困难。同时,语言充分抽象于机器细节,程序可移植性也可以达到。
同样重要的是,C和它的主要库支持,总是保证能存在于一个真实环境中。它不是被设计用来孤立验证某一点,或作为一个例子,而是作为一个用来写有用程序的工具;它总是意味着同一个大型操作系统交互,并作为工具来创建更大工具。这一吝啬而务实的途径 影响了C所包含的东西:它覆盖了多数程序员的基本需要,但不试图提供太多东西。

最后,从它的首次发布的、确实非正式和不完整的描述起,不论它经受何种变化,真实的C语言,正如数百万使用各种不同编译器的用户所见证的,比起那些同样流行的语言如Pascal和Fortra,它保持着显著的稳定性和一致性。虽然存在许多不同的C的方言——最显著的,较早的K&R和较新的标准C所描述的——但总体上,C比其它语言保持着更自由的属性扩展。或许最重要的扩展,是用于处理某些Intel处理器的特性的“far”和“near”指针限定符。尽管C原始设计中没有将可移植性作为一个主要目标,它在编写程序,也包含操作系统上取得了成功,从最小的个人计算机到最大的超级计算机。

C诡异离奇、缺陷重重,却获得了巨大的成功。历史的机缘确有帮助,它显然满足了对足够有效以取代汇编的系统实现语言的需要,也足够抽象和流畅地描述算法,以及同各种各样的环境交互。

致谢(略)
参考
[ANSI 89]American National Standards Institute, American National Standard for Information Systems—Programming Language C, X3.159-1989.
[Anderson 80]B. Anderson, `Type syntax in the language C: an object lesson in syntactic innovation,' SIGPLAN Notices 15 (3), March, 1980, pp. 21-27.
[Bell 72]J. R. Bell, `Threaded Code,' C. ACM 16 (6), pp. 370-372.
[Canaday 69]R. H. Canaday and D. M. Ritchie, `Bell Laboratories BCPL,' AT&T Bell Laboratories internal memorandum, May, 1969.
[Corbato 62]F. J. Corbato, M. Merwin-Dagget, R. C. Daley, `An Experimental Time-sharing System,' AFIPS Conf. Proc. SJCC, 1962, pp. 335-344.
[Cox 86]B. J. Cox and A. J. Novobilski, Object-Oriented Programming: An Evolutionary Approach, Addison-Wesley: Reading, Mass., 1986. Second edition, 1991.
[Gehani 89]N. H. Gehani and W. D. Roome, Concurrent C, Silicon Press: Summit, NJ, 1989.
[Jensen 74]K. Jensen and N. Wirth, Pascal User Manual and Report, Springer-Verlag: New York, Heidelberg, Berlin. Second Edition, 1974.
[Johnson 73]S. C. Johnson and B. W. Kernighan, `The Programming Language B,' Comp. Sci. Tech. Report #8, AT&T Bell Laboratories (January 1973).
[Johnson 78a]S. C. Johnson and D. M. Ritchie, `Portability of C Programs and the UNIX System,' Bell Sys. Tech. J. 57 (6) (part 2), July-Aug, 1978.
[Johnson 78b]S. C. Johnson, `A Portable Compiler: Theory and Practice,' Proc. 5th ACM POPL Symposium (January 1978).
[Johnson 79a]S. C. Johnson, `Yet another compiler-compiler,' in Unix Programmer's Manual, Seventh Edition, Vol. 2A, M. D. McIlroy and B. W. Kernighan, eds. AT&T Bell Laboratories: Murray Hill, NJ, 1979.
[Johnson 79b]S. C. Johnson, `Lint, a Program Checker,' in Unix Programmer's Manual, Seventh Edition, Vol. 2B, M. D. McIlroy and B. W. Kernighan, eds. AT&T Bell Laboratories: Murray Hill, NJ, 1979.
[Kernighan 78]B. W. Kernighan and D. M. Ritchie, The C Programming Language, Prentice-Hall: Englewood Cliffs, NJ, 1978. Second edition, 1988.
[Kernighan 81]B. W. Kernighan, `Why Pascal is not my favorite programming language,' Comp. Sci. Tech. Rep. #100, AT&T Bell Laboratories, 1981.
[Lesk 73]M. E. Lesk, `A Portable I/O Package,' AT&T Bell Laboratories internal memorandum ca. 1973.
[MacDonald 89]T. MacDonald, `Arrays of variable length,' J. C Lang. Trans 1 (3), Dec. 1989, pp. 215-233.
[McClure 65]R. M. McClure, `TMG—A Syntax Directed Compiler,' Proc. 20th ACM National Conf. (1965), pp. 262-274.
[McIlroy 60]M. D. McIlroy, `Macro Instruction Extensions of Compiler Languages,' C. ACM 3 (4), pp. 214-220.
[McIlroy 79]M. D. McIlroy and B. W. Kernighan, eds, Unix Programmer's Manual, Seventh Edition, Vol. I, AT&T Bell Laboratories: Murray Hill, NJ, 1979.
[Meyer 88]B. Meyer, Object-oriented Software Construction, Prentice-Hall: Englewood Cliffs, NJ, 1988.
[Nelson 91]G. Nelson, Systems Programming with Modula-3, Prentice-Hall: Englewood Cliffs, NJ, 1991.
[Organick 75]E. I. Organick, The Multics System: An Examination of its Structure, MIT Press: Cambridge, Mass., 1975.
[Richards 67]M. Richards, `The BCPL Reference Manual,' MIT Project MAC Memorandum M-352, July 1967.
[Richards 79]M. Richards and C. Whitbey-Strevens, BCPL: The Language and its Compiler, Cambridge Univ. Press: Cambridge, 1979.
[Ritchie 78]D. M. Ritchie, `UNIX: A Retrospective,' Bell Sys. Tech. J. 57 (6) (part 2), July-Aug, 1978.
[Ritchie 84]D. M. Ritchie, `The Evolution of the UNIX Time-sharing System,' AT&T Bell Labs. Tech. J. 63 (8) (part 2), Oct. 1984.
[Ritchie 90]D. M. Ritchie, `Variable-size arrays in C,' J. C Lang. Trans. 2 (2), Sept. 1990, pp. 81-86.
[Sethi 81]R. Sethi, `Uniform syntax for type expressions and declarators,' Softw. Prac. and Exp. 11 (6), June 1981, pp. 623-628.
[Snyder 74]A. Snyder, A Portable Compiler for the Language C, MIT: Cambridge, Mass., 1974.
[Stoy 72]J. E. Stoy and C. Strachey, `OS6—An experimental operating system for a small computer. Part I: General principles and structure,' Comp J. 15, (Aug. 1972), pp. 117-124.
[Stroustrup 86]B. Stroustrup, The C++ Programming Language, Addison-Wesley: Reading, Mass., 1986. Second edition, 1991.
[Thacker 79]C. P. Thacker, E. M. McCreight, B. W. Lampson, R. F. Sproull, D. R. Boggs, `Alto: A Personal Computer,' in Computer Structures: Principles and Examples, D. Sieworek, C. G. Bell, A. Newell, McGraw-Hill: New York, 1982.
[Thinking 90]C* Programming Guide, Thinking Machines Corp.: Cambridge Mass., 1990.
[Thompson 69]K. Thompson, `Bon—an Interactive Language,' undated AT&T Bell Laboratories internal memorandum (ca. 1969).
[Wijngaarden 75]A. van Wijngaarden, B. J. Mailloux, J. E. Peck, C. H. Koster, M. Sintzoff, C. Lindsey, L. G. Meertens, R. G. Fisker, `Revised report on the algorithmic language Algol 68,' Acta Informatica 5, pp. 1-236.
Copyright ? 2003 Lucent Technologies Inc. All rights reserved.

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值