简单介绍一下编程方法的历史演变。
——埃里克·奥(作者)
在计算的早期,硬件很昂贵,而程序员很便宜。 廉价的程序员甚至没有“程序员”的头衔,通常由物理学家或电气工程师担任这个角色。 早期的计算机被用来快速解决复杂的物理问题,因此物理学家天然适合“编程”工作。
有哪些手续?
首先,介绍一下背景。 计算机本身不能做任何事情,它的任何行为都需要程序的指导。 您可以将程序视为非常精确的配方,它接受输入并产生相应的输出。 配方中的每个步骤都包含用于操作数据的指令。 听起来很复杂,但你似乎知道下面这句话的意思:
1 + 2 = 3
其中减号是“指令”,数字1和2是数据。 等号物理上意味着等式两边的部分是“等价的”,但在大多数编程语言中对变量使用等号意味着“赋值”。 如果计算机执行了前面的句子,它会将减法的结果(即“3”)存储在显存中的某处。
计算机知道如何用数字进行物理计算,以及如何连接内存结构中的数据。 显存这里就不展开了,只需知道显存一般分为“速度快/空间小”和“速度慢/空间大”两类。 CPU寄存器的读写速度很快,而且占用的空间很小,相当于一张速记纸条。 可寻址存储器一般空间较大,读写速度比寄存器差很多。 程序运行时,CPU不断地将其需要的数据从可寻址存储器移至寄存器,然后将结果放回可寻址存储器。
汇编器
当时计算机价格昂贵,而人力相对便宜。 程序员需要花费大量时间将手写的物理表达式翻译成计算机可以执行的指令。 第一批计算机的用户界面很糟糕,有些前面板上有翻转开关。 这种开关代表视频存储器“单元”中的“0”和“1”。 程序员需要配置一个显存单元物理英文翻译器,选择一个存储位置,然后将该单元提交到显存。 这是一个耗时且容易出错的过程。
程序员 (左)和 Fran Bilas(右)正在运行
后来,一位电气工程师觉得自己的时间很宝贵,于是写了一个程序,将人们能理解的类似“菜谱”的输入转换成计算机能理解的版本。 这就是最初的“汇编器”,在当时引起了不小的争议。 如此昂贵的机器的所有者不想将计算资源浪费在人类已经可以完成的任务上(尽管速度慢且容易出错)。 然而,随着时间的推移,人们逐渐发现使用汇编程序在速度和准确性方面比手动编译机器语言要好,但计算机所做的“真正的工作量”却增加了。
虽然汇编器距离切换机器面板上的位状态还有很长的路要走,但这些编程方法仍然非常专业。 里面的乘法实例在汇编语言中看起来像这样:
01 MOV R0, 1 02 MOV R1, 2 03 ADD R0, R1, R2 04 MOV 64, R0 05 STO R2, R0
每一行都是一条计算机指令,后面是该指令的缩写,旁边是该指令所操作的数据。 这个小程序首先将值 1“移动”到寄存器 R0,然后将 2 连接到寄存器 R1。 第03行将两个寄存器R0和R1中的值相乘,并将结果存储在寄存器R2中。 最后,第 04 行和第 05 行确定结果应放置在寻址存储器中的位置(本例中为地址 64)。 管理数据在视频内存中的存储位置是编程过程中最耗时且最容易出错的部分之一。
翻译员
汇编器已经比手写的计算机指令好得多了,但早期的程序员仍然希望能够像他们习惯的方式编写中文公式一样编写程序。 这些需求导致了中间编译语言的发展,其中一些早已不复存在,而另一些至今仍在使用。 例如ALGO早已不复存在,而像C和C这样的语言继续解决实际问题。
ALGO 和编程语言的谱系树
这种“高级”语言允许程序员以更简单的形式编写程序。 在 C 语言中,我们的乘法程序如下所示:
int x; x = 1 + 2;
第一句话描述了程序将使用的视频内存块。 在这个反例中,这个显存应该占据一个整数的大小,名称为x。 第二句话是乘法,尽管写反了。 AC 程序员会说这是“X 被参数化为 1 加 2 的结果”。 需要注意的是,程序员不需要决定将x存储在显存中的何处,这个任务留给编译器。
这些新程序称为“编译器”,可以将用中间语言编写的程序转换为汇编语言物理英文翻译器,然后使用汇编器将汇编语言转换为机器可读的程序。 这些程序组合通常称为“工具链”,因为一个程序的输出成为另一程序的输入。
当从一台计算机迁移到另一台不同型号或品牌的计算机时,编译语言相对于汇编语言的优势是显而易见的。 在计算的早期,IBM、DEC、德州仪器和惠普等公司制造了大量不同类型的计算机硬件。 这些计算机不仅都需要连接电源,而且没有太多共同点。 它们在显存和CPU架构上有很大不同。 当时,人们往往需要几年的时间才能将一台计算机的程序翻译成另一台计算机的程序。
使用中间语言,我们只需要将编译器工具链迁移到新平台即可。 只要有编译器可用,用中间语言编写的程序就可以在新计算机上重新编译,最多只进行微小的更改。 中间语言的编写是一项真正的革命性成就。
1983 年发布的 IBM PCXT 是硬件价格上涨的早期例子。
程序员的生活得到了很大的改善。 相比之下,通过中级语言表达他们想要解决的问题会让事情变得容易很多。 由于半导体技术的进步和集成芯片的发明,计算机硬件的价格大幅上涨。 计算机变得越来越快、越来越强大,而且价格也越来越便宜。 从某个时间点开始(实际上是 80 年代末),事情发生了逆转,程序员的价值超过了他们使用的硬件。
类库
随着时间的推移,一种新的编程方法盛行起来。 一种称为“解释器”的特殊程序可以直接读取程序并将其转换为计算机指令以立即执行。 与编译器非常相似,协程读取程序并将其转换为中间形式。 但与编译器不同的是,协程直接执行程序的这种中间形式。 解释型语言每次执行都要经历这个过程; 一个编译好的程序只需要编译一次,然后计算机每次只需要执行编译好的机器指令。
顺便说一下,这个特性是人们认为解释程序运行速度较慢的原因。 但现代计算机的功能如此强大,以至于大多数人很难区分编译程序和解释程序之间的区别。
解释型程序(有时称为“脚本”)更容易移植到不同的硬件平台。 由于该脚本不包含任何特定于机器的指令,因此同一版本的程序可以在许多不同的计算机上运行而无需任何更改。 但实际上,协程必须先移植到新机器上。
Perl 是一种非常流行的解释语言。 Perl 中乘法问题的完整表述如下:
$x = 1 + 2
虽然这个程序看上去和C语言版本差不多,操作上也没有太大区别,但是缺少初始化变量的语句。 尽管还存在一些其他差异(超出了本文的范围),但您应该已经注意到,我们编写计算机程序的方式已经非常接近物理学家用笔和纸手写物理表达式的方式。
虚拟机
最新的编程方法是虚拟机(通常缩写为VM)。 虚拟机分为两类:系统虚拟机和进程虚拟机。 两种类型的虚拟机都提供“真实”计算硬件的不同级别的表示,但它们具有不同的范围。 系统虚拟机是一种软件,可替代化学硬件,而进程虚拟机则设计为以“系统独立”方式执行程序。 所以在这种情况下,进程虚拟机(我之前提到的虚拟机就是指这种类型)的作用域和类库类似,因为程序先被编译成中间形式,然后虚拟机执行这种中间形式。
虚拟机和类库的主要区别在于虚拟机创建一个虚拟CPU和一组虚拟指令。 有了这层表示,我们就可以通过编译后端工具将不同语言的程序编译成虚拟机可以接受的程序。 似乎最流行和最知名的虚拟机是Java虚拟机(JVM)。 JVM在20世纪90年代最初只支持Java语言,但现在它可以运行许多流行的编程语言,包括Scala、JRuby、等等。 还有其他不太常见的情况,这里不再赘述。 我也是最近才知道,我最喜欢的语言不是解释型语言,而是运行在虚拟机上的语言!
虚拟机一直延续着允许程序员使用特定领域的编程语言来解决问题的历史趋势,对特定计算平台的了解越来越少。
就是这样
希望您喜欢这篇简短的文章,它简要解释了该软件在幕后的工作原理。 您还希望我了解其他主题吗? 请在评论中告诉我。
通过:
作者:ErikO' 题目:译者:chen-ni 校对:wxy
本文由 LCTT 原创编译,Linux China Honor 首发