我们真的是走过了很长的路,从第一篇的琥珀开始,到上一篇的存储器从对自然规律的探索,到对硬件的控制。
CPU、内存、存储,以及各种输入输出设备,一个完整的计算机硬件体系终于形成了。
可是,它仍然一句话也听不懂。
你对着它说:“加一下这两个数。”它听不懂。你又说:“保存这个文件。”它还是听不懂。
它唯一能听懂的语言,只有一种——0和1。在电路中,“有电”是1,“没电”是0。这是它从出生起就认识的全部词汇。而人类用的是自然语言,计算机用的却是二进制。这是机器和人之间一道无法绕开的墙。
于是,一个持续了六十年(从1945年冯·诺伊曼提出存储程序思想算起,到2005年左右,高级语言和操作系统已经足够成熟)的问题摆在了所有人面前:怎么才能让计算机“听懂”人话?
一、机器码——什么都得自己写
最早的程序员,真的是在“喂”计算机。他们用手在纸带上打孔——有孔是1,没孔是0。一条纸带就是一段程序。
程序员先用手写出一串0101,然后用打孔机在纸带上打出对应的孔,再把纸带喂进计算机。
计算机读一行,执行一行。
假设今天让你写这样一段程序:
00100101101101000100101111101010
看上去太熟悉了,但又是那么的陌生。这就是机器码,计算机唯一听得懂的语言。
但问题是,三天以后,你还能看懂吗?
纸带不光难写,还特别容易出错。程序员辛苦打一星期的纸带,如果某一个孔出错了,就得全部重来。而且每一台计算机的“语言”都不一样——IBM的机器码和UNIVAC完全不同。同样的功能也得重新编写,为这台机器写的程序,换一台就废了。
还有就是这堆由0和1组成的程序里,真正占大多数的,并不是"计算",而是各种控制指令——管寄存器、管地址、管内存布局、管指令顺序——CPU的每一个动作,都要用手写0101来指挥。

二、汇编语言——不用记0101了
机器码太难用了,我甚至感觉都有点同情他们。终于有人开始想:能不能用一些简单的“缩写”来代替0101?
比如:用ADD代表加法,SUB代表减法,JMP代表跳转。程序员写ADD A, B,然后交给一个提前写好的程序,由它把ADD翻译成对应的0101。
还真有,这个程序就叫做汇编语言。程序员终于不用背0101了。
但有一个问题:汇编语言和机器码是一一对应的。 你写一行ADD,汇编器就翻译成一条机器指令。
这个语言的好处是显而易见的,终于不用再对着一点也看不懂的数字发呆了,至少有了语义。
但是,它只是一个翻译工具,没有简化程序员的思考负担。所以,程序员还是必须理解CPU的内部结构——要记住寄存器、地址、指针、堆栈。一个加法计算器,用汇编可能要写几十行。而且换一台CPU,指令集不同,汇编语言也得跟着换。程序员学的知识,只能在同一个CPU系列里用。
汇编语言解决了一个问题:不用背0101了。 但没有解决另一个问题:怎么才能不关心CPU长什么样?
三、高级语言——终于不用研究CPU了
科学家们受够了。他们天天算导弹轨迹、算桥梁应力、算天气预报,却要花大把时间写机器码和汇编。终于有人说:不行,我要写一种像数学一样的语言。
1957年,第一个真正意义上的高级语言Fortran诞生了。它的目标很简单:让程序员用数学公式一样的写法来描述计算。
例如,你要算a + b,在Fortran里就写A = B + C。编译器会把它翻译成汇编,再翻译成机器码。
程序员终于不再需要知道CPU有几个寄存器、不需要知道地址怎么算、不需要管内存布局。他只需要写:“把这两个数加起来,结果放到这里”。那种感觉是真的好。
而完成这个翻译的,叫编译器。它第一次成为人与机器之间的“翻译官”。
编译器是比汇编器更强大的翻译工具——它把你写的A = B + C变成一串汇编指令,再变成一长串0101。不仅仅如此,虽然不同CPU的指令集不同,但同一个高级语言程序,只需要换一个编译器,就能跑在不同机器上。
这带来了一个巨大的变化:程序开始可以脱离硬件了。 同一个Fortran程序,可以在IBM上编译运行,也可以在UNIVAC上编译运行,只要各自有对应的编译器。
随后出现了C语言,比Fortran更灵活、更接近底层。它成了操作系统和系统软件的主流语言。再后来,Pascal、BASIC、C++、Java、Python……每一种语言都在做同一件事:程序员可以不用研究CPU,而专心研究问题本身。

注:这背后还有一位关键人物:格蕾丝·霍珀。
她是美国海军军官,也是最早提出“编译器”概念的人。她发明的第一个编译器叫A-0,后来发展出COBOL语言。她还贡献了一个流传至今的故事——1947年,她在调试Mark II计算机时,发现继电器里卡了一只飞蛾。她把飞蛾贴在日志上,写下了“First actual case of bug being found”——从此,程序错误被称为Bug,排除错误被称为Debug。
今天的程序员,大多数已经不需要知道CPU内部长什么样。他们只需要会写Java或Python,编译器替他们操心一切。

四、操作系统——不用重复造轮子了
看起来似乎完美了,高级语言解决了“怎么写程序”的问题。但程序跑起来之后,还会遇到另一个麻烦:每个程序都要自己管其它硬件。
假设你写一个计算器。为了显示数字,你要自己驱动显示器;为了保存数据,你要自己控制磁盘;为了输入数字,你要自己读取键盘;为了申请内存,还要自己管理RAM。那程序根本不用写了。
所有程序都在重复做同一套脏活累活——管硬件、管内存、管文件。很快,程序员们意识到:这些活不应该让每个程序自己做。
于是出现了操作系统。
它是一个永远在后台运行的程序,负责统一管理计算机的所有硬件资源。CPU、内存、磁盘、键盘、显示器——全部由操作系统接管。其他程序只需要说:“我要一个窗口”“我要一个文件”“我要一段内存”,剩下的全部由操作系统搞定。
1960年代,IBM的System/360大型机已经有了操作系统的雏形。1970年代,UNIX的出现让操作系统成为计算机的标准组件。到了1980年代,微软的DOS和Windows、苹果的Mac OS,把操作系统带到了个人电脑上——不需要专业训练,点一点就能用。
操作系统的核心价值是:为程序提供一个“干净的世界”。 程序不需要知道显示器是什么型号、键盘是什么接口、磁盘是机械还是固态——操作系统替它挡住了这一切。
它替程序员省掉了最麻烦的事:不用重复造轮子了。

五、软件革命——一条持续的抽象之路
从机器码到汇编,从汇编到高级语言,从高级语言到操作系统——你可能会问:这一层层的“翻译”,到底在做什么?
答案是:把复杂藏起来。
机器码暴露CPU的所有细节。汇编语言隐藏了0101的写法,但暴露了寄存器。高级语言隐藏了寄存器,但暴露了内存管理。操作系统隐藏了硬件细节,让程序在“干净的世界”里运行。
每一层都在做同一件事:把底层的复杂性往更深处推一层,让上面的人更轻松。
在早期计算机时代,软件是“赠品”——买IBM的大型机,软件免费送。后来有人开始单独卖软件,整个行业都觉得不可思议:软件还能卖钱?
结果到了今天,微软几乎不生产CPU,却成了全球最大的科技公司之一。一部手机的硬件成本可能只有几百块,但它跑的操作系统和生态,让它的价值翻了十倍。软件第一次摆脱了硬件的附属地位,成为能够独立创造巨大价值的产业。
你今天写一段Java程序,它跑在Windows上,Windows跑在Intel芯片上,Intel芯片执行的仍然是0101。你写的Java代码,从来没有被CPU直接执行过——它被编译器翻译成字节码,被JVM翻译成机器码,最后才变成0101。一层一层,全部是抽象。
如果说机器码到高级语言是把“硬件细节”藏了起来,操作系统是把“硬件管理”藏了起来,那么AI正在做的,是把“编程本身”藏了起来。
过去你写代码告诉计算机每一步怎么走。现在你告诉AI“你想要什么”,它自己生成代码、自己调试、自己运行。程序员从“怎么写”变成了“想要什么”。
这是最新的一层抽象。它还没有完全成熟,但方向已经清晰——计算机离人类思维,又近了一步。
计算机发展的历史,就是不断建立抽象层的历史。每一次抽象,都把“底层复杂性”往更深处藏了一层,让程序员离硬件越来越远,离人类思维越来越近。
而这些抽象层叠在一起,就构成了我们今天习以为常的世界。人类没有让计算机变简单,而是让程序员越来越不用面对复杂。

计算机终于有了大脑、记忆、灵魂。但到目前为止,它一直是一个“孤岛”——一台计算机独自工作,与世界隔绝。
而真正的信息时代,是从计算机学会互联开始的。
下一篇,互联网——计算机如何连接在一起,并改变了我们的一切。
——本文封面及配图由AI生成,仅供参考。内容为作者原创思考。
夜雨聆风