热度 3
2022-5-28 14:25
1203 次阅读|
0 个评论
写在前面 它们不厌其烦地执行人的指令;它们收集世间万物的知识,供人顷刻之间随心调取;它们是现代社 会 的 中流砥柱,但其存在却往往备受忽 视。 它们就是计算机,是人类迄今为止最伟大的发明成就,是登峰造极、至高无上的终极工 具 。 计算机科学的问 世,推动了人类历史上最非比寻常的社会变革之一。 而 = = 编程语言 == 作为计算机的灵魂,存在感却远远高于计算机,它就像一个纽带把我们和计算机深深的 联系在了一起 。 编程语言 的 发展更是和计算机的演变有着密不可分的关系。 不 知道大家有没有好奇过,世界上第一门编程语言是什么? 今天就由我带领大家穿越到这一切的起点,去看一看计算机和编程语言的爱恨情仇 。 正文 图灵机 不 同的的人面对计算机有着不同的给关注点,有人觉得计算机的设计很巧妙,有人觉得计算机的结构布 置很酷,有人觉得计算机的界面很漂亮 … … 但计算机的美妙之处并 不在于其闪烁的灯光、旋转的磁盘、成排的芯片和电线,而在于, 这些部件的背 后隐藏着一个优雅而简单的想法。这个想法同晶体管、操作系统、网络和文字处理器毫无关联,也不 可 能 有 任何关联,因为它的诞生时间比这些设备都早。 图灵的相关生平,这里不多做赘述,这里我们只关注他的 “ 可计算性理论 ” 。 还 记得当时初学冯诺依曼结构时,我们班里的同学还就冯诺依曼机与图灵机谁的贡献最大,而吵的不可 开交,最后也是谁也没说服谁 。 冯诺依曼机大家都不陌生,可以简单地理解成冯诺依曼机更侧重于硬件的实 现 。 图灵 机 偏重的抽象模型是 “ 可计算 ” 和 “ 不可计算 ” 这个计算机的边界 1. 世界上有很 多问题,其中只有一小部分是数学问题; 2. 在 数 学问题中,只有一小部分是有解的; 3. 在 有解的问题中,只有一部分是理想状态的图灵机可以解决的; 4. 在后一 类的问题中,又只有一部分是今天实际的计算机可以解决的。 这 个时候可能有人就要说了,这和今天要讲的世界上第一个编程语言有什么关系?你这不是上来就先给 计算机定下了一个边界了吗 ? 是的,先展示这段的目的就是为了告诉大家: 不要迷信计算机,不要迷信我们的编程语言。 不 管是在人工智能和深度学习大行其道的今天,有些问题也是无法用计算机去解决的,我们要始终怀着 一种敬畏之心来面对这个世界。 打孔卡片 这一 切都要从打孔卡片开始说起。 美国宪法中要求, 每 10 年就得进行一次人口普查。到了 19 世纪末期,人口增长的实在是太频繁了,以至 于 18 8 0 的人口普查历时 8 年才最终完成,当时还都是通过纸和笔来完成的。 1890 年 , Herman Hollerith 被授命去解决这一问题,他最终使用了穿孔卡来存储数据,并用一台制表机 ( tabulating machine )来进行统计和排序。 在 2 0 世纪的大部分时间里,穿孔卡在数据处理行业得到了广泛的应用, 其中专业且日益复杂的单元记 录机器被组织成半自动数据处理系统,使用穿孔卡进行数据输入、输出和存储 。 1896 年, Hollerith 成立了制表机器公司,开始了自己的事业。他把自己的设备和卡片出售给大的保 险公 司 ,以及包括英国,意大利,德国,俄罗斯,澳大利亚,加拿大,法国,挪威,波多黎各,菲律宾等国 在内 的多国政府。 他的公司后来跟别 的 公司进行了合并,并在 1924 年最终成为了国际商业机器公司。没错,它就是 IBM 。 这就是我们的第一站:打孔机和打孔卡片 。 有 人可能会有疑问,这打孔卡片也算是一门编程语言吗?这就要看大家怎么去定义编程语言了。 在 我看来,只要其涉及数据处理与一定的计算规则都可以称为一种语言。就像我们常说的: 程 序 = 数据 + 算法 哪怕这 些数据只是最常见的自然数,哪怕这些算法只是加减乘除。 机器代码 打孔卡片靠其出 色的能力盛行了一段时间,但你能想想那硕大的机器和成吨种的卡片吗? 幸运的是这些都只是暂时的,而拯救我们的就是电子学与计算机科学的结合,让我们脱离了笨重的机械 式计 算机。 晶体管的出现更是让 “ 开 / 关 ” 动作变 得简洁又优雅。 而 我们这次的主角 —— 机器代码,就是这一开一关动作的化身: 0 和 1 。 机 器 代码之所以被称为机器代码,就是因为这种代码是可以直接被机器(计算机)所读取。 用二进制代码表示的计算机能直接识别和执行的一种机器指指令系统令的集 合 。 大 家 可以随便打开一个自己用任何一种高级语言编译好的二进制文件( . bin )来查看这些机器码到底长 什么 样子。 最右边就是我们的机器码,但为什么不是 01 组合,怎么还有其他数字和字母呢 ? 这是因为二进制表示的数字实在是太小了,所以大多采用的是十六进制来表示 。 汇编语言 用机器语言编写程序,编程人员要首先熟记所用计算机的全部指令代码和代码的涵义 。 手编 程序时, == 程序员得自己处理每条指令和每一数据的存储分配和输入输出,还得记住编程过程中每 步所使用的工作单元 处在何种状态 == 。这是一件十分繁琐的工作。 编写程序花费的时间往往是实际运行时间的几十倍或几百倍,而且, == 编出的程序全是些 0 和 1 的指令代 码 ,直观性差,还容易出错 == 。 那么有没有一种方式, 让我们能够更容易的记住这些机器指令? 汇编语言闪亮 登场。 汇编语言的主体是汇编 指 令。汇编指令和机器指令的差别在于指令的表示方法上, 汇编指令是机器指令 便于记忆的书写格式。说 白了,汇编语言就是 == 助记符 == ( Mnemonics )。 可能有人会问,我们用 汇 编语言编写程序,可是计算机只认识机器指令,那该怎么办? 这时候就需要一 个能将汇编语言转换成机器指令的工具,我们称其为编译器。程序员用汇编语言写出源代码,再用 汇 编 编 译器将其编译为机器码,最后由计算机执行。 再者,汇编语言指令是机器指令的一种符号表示,而不同类型的 CPU 有不同的机器指令系统,也就有 不 同的汇编 语言,所以, == 汇编语言程序与机器有着密切的关系 == 。 所以,除了同系列、不同型号 CPU 之间的汇编语言程序有一定程度的可移植性之外,其它不同类型 (如:小型机和微机等) CPU 之间的汇编语言程序是无法移植的,也就是说, == 汇编语言程序的通用性 和可 移 植性要比高级语言程序低 == 。(因为高级语言可以再不同类型的计算机上用不同的编译器翻译成 机 器语言) Fortran Fortran 语 言 最初是由 IBM 公司在 50 年代开发的。 当 时,创建语言的目的是专门解决一组特定的问题: Fortran 语言的目的是科学处理。 它仍然是在高性能计算领域最流行的语言之一,而且作为基准,用于世界最快的超级计算机程序的 语 言 的 排名。 Fortran 语言建立使 用 星号乘法,这是今天仍在使用的所有语言中的约定。 这是它的外 观: CO BOL COBOL ( Common Business - Oriented Language ) 被 设计用于商业用途。这是企图使编程语言更类似于英语,让程序员和管理人员可以读取它。 它的设计者有 Grace Hopper (发现 “ Bug ” 的人),以及发明了类似英语的数据处理语言 FLOW - MATIC 的人,也是 最 合适,帮助创建一个看起来类似英文通用商业语言的人选。 这 是一个 COBOL 的 Hello World 程序 : IDENTI FICATION DIVISION . PROGRA M - ID . HELLO - WORLD . ENVIRO NMENT DIVISION . DATA D IVISION . PROCED URE DIVISION . MAIN . DI SPLAY ' Hello , world .' . ST OP RUN . ALGOL 60 ( ALGOrithmic Language 1960) 是一个委员 会 推动的,非常好,有影响力的语言 , 发布于 1960 年。 它从来没有得到普及, 但 它推出了许多重要概念,包括摆脱 GOTO 。在行与行之间跳来跳去行的语言, 如 BASIC ,难以遵循程序的流程,导致编写 程序容易出错。 ALGOL 60 引入结构化程序设计和模块:它使用 BEGIN 和 END (因为大括号是不可用),感谢 ALGOL 60 现在我们有了代码块,而不是 GOTO 。 ALGOL 也不希望太过专业,从而适合良好的科学和业务处理 下面是 它的样子: procedure Absmax(a) Size:(n, m) Result:(y) Subscripts:(i, k); value n, m; array a; integer n, m, i, k; real y; comment The absolute greatest element of the matrix a, of size n by m is transferred to y, and the subscripts of this element to i and k; begin integer p, q; y := 0; i := k := 1; for p:=1 step 1 until n do for q:=1 step 1 until m do y then begin y := abs(a ); i := p; k := q end end Absmax P ascal Pascal 是在 1968 - 1969 年设计 , 由 Niklaus Wirth 出版于 1970 年,其灵感来自 ALGOL 它最初是非常流行的,虽然最初设计为教学工具,很长一段时间很多人用它做通用编程。 但是,它 不是模块化不够,有一些使得编程难的设计挑战。 比 如有一个片段 : while a b do WriteLn ( ' Waiting ' ) ; if a b then WriteLn ( ' Condition met ' ) { no semicolon allowed ! } else WriteLn ( ' Condition not met ' ); for i : = 1 to 10 do { no semicolon for single statements allowed ! } WriteLn ( ' Iteration : ' , i ); r epeat a : = a + 1 until a = 10 ; case i of 0 : Write ( ' zero ' ); 1 : Write ( ' one ' ); 2 : Write ( ' two ' ); 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 : Write ( '?' ) end ; B 在贝尔实验室开发于 1969 年 , 它的灵感来自于 Fortran 和 BCPL 。 还 记得有个同学开玩笑说,既然有 C 语言,那肯定会有 B 语言和 A 语言,没想到还真有 B 语言(其实还有个 E 语 言就不说了)。 B 引入 了 += 操作符 ( 尽管写成 =+), 以及自增 / 自减操作符 ( ++ 和 – ) printn ( n , b ) { extrn putchar ; auto a ; if ( a = n / b ) /* assignment , not test for equality * / printn ( a , b ); /* recursive * / putchar ( n % b + '0' ); } C 语言 C 诞生于 B 加上从 Pascal 加入一些好的想法。它是在贝尔实验室(再次)的 Dennis Ritchie 在 1969 年 和 1973 年之间开发。 相比较于机器语言与汇编语言来说, C 已经拥有 == 更强的表达能力,可方便地表示数据的运 算和程序的 控制结构 ,能更好的描述各种算法,而且容易学习掌握 == 。 但 高级语言编译生成的程序代码一般比用汇编程序语言设计的程序代码要长,执行的速度也慢。 关于编程语言就说到这里,如果把每一门语言都说一遍的话,可能几天几夜都说不完 。 感兴趣的同学可以去维基百科上看一 看 第一个编译器是什么语言编译的?自举 除了第 一个编程语言外,相信大家肯定还有一个疑问: 世界上第一个编译器使用什么语言来编译的? 这 就 类似于那个世界上是先有鸡还是先有蛋的问题。 其实在编译原理中,有一个概念:自 举 。 == 编程语言是自举的 == ,指的是说,我们能用自己写出来的程序编译自己。但是自举,并 不要求这门语 言的 第一个编译器就是用自己写的。 比 如,这里说到的 Go ,先是有了 Go 语言,我们通过 C ++ 写了编译器 A 。然后呢,我们就可以用这个 编译器 A ,来编译 Go 语言的程序。接 着,我们再用 Go 语言写一个编译器程序 B ,然后用 A 去编译 B , 就得到了 Go 语言写好的编译器的可执行文件了。这个之后,我们就可以一直用 B 来编译未来的 Go 语 言程序,这 也就实现了所谓的自举了。 更详细的关于鸡蛋 问题,可以直接看 Wikipedia 上这个链接,里面讲了多种这个问题的解决方案。 https://en.wikipedia.org/wiki/Bootstrapping_(compilers) 写在最后 在上文 中 ,我们大致了解了计算机和编程语言的发展史。 如果从严谨一点的角度去考虑的 话, Fortran 语言应该是世界上第一门高级编程语言。 编程语言千千 万,这些语言之间没有高低贵贱,更不存在什么歧视链, 有的只有不同的应用环境适合哪 一种编程语言。 最后 祝愿大家不管使用哪一种语言都能 bug 少少 !!! ( 室友和同门都申请离校回家了,我还悲惨的在学校呆 着,可快点解封吧 ~ 我要出去吃烧烤,吃火锅! ) 参 考 文献: 《 计 算机 : 一部历史》彼得 · 本特利 http://foorious.com/articles/brief-history-of-programming-languages/ https://segmentfault.com/a/1190000004303544 https://time.geekbang.org/column/article/91793 https://www.cnblogs.com/ysocean/p/7580162.html