如何在1天内学会1门语言?(序章)计算机基础知识准备

77 阅读15分钟

当你去问一个从事编程行业多年的程序员,学习某种语言难不难时,他们可能会说:“学不难,难的是应用。” 对于一个久经沙场的程序员来说,学习编程语言本身并不是什么难事。本文不讲应用,本文讲的就是如何学习编程本身,相当于学习编程的“内功心法”。有了这个心法,学习任何编程语言都会事半功倍。

叠甲:这是一篇“不求甚解”的文章,所有的知识最多只会涉及表面。本文的目标是让你了解最重要的概念,对计算机编程有一个大概的知识框架,起到指明方向的作用。本文(之后可能会出视频)面向的是零基础的编程小白。本文的所有概念都基于我的经验,如果和您的理解相左,那您对了。

到底什么是程序呢?

很多编程语言教程的第一步,或者大学科班学习编程语言的第一课,就是打印一个字符串“Hello, world”。这被誉为经典之作,也是每个新手程序员的第一个目标程序。

很多没有计算机背景的新手开始学习编程之前,其实对什么是”程序“,什么是编程都不了解。对于当今时代的人来说,普通人所理解的“程序”可能是一个“网页”或者一个“手机APP”。然而,从“Hello, world”进阶到写出一个“网页”或“手机APP”,这个过程似乎总是被编程老师一笔带过。他们通常会告诉你:“那个目标距离你还很远,现在你需要学习的是基础。未来你一定能做到写出一个应用程序。”

然而,我认为,新手程序员不能一头扎进枯燥的基础编程知识里,否则很容易陷入困惑,不理解简单代码操作的意义,从而对编程失去兴趣。所以,在本文的序章里,我会尽量帮助你理解“程序的本质”以及一个“应用程序”是如何构成的。理解了程序的本质后,在后续的学习中,你就能清楚地知道自己什么时候能够做出一个完整的应用程序。

程序的本质,其实就是计算机对信息的处理和输出(Input/Output,也叫I/O),编程,就是人类对机器进行操控。牢记这句话,后面要考。 现在我要给你简单的讲讲计算机组成原理的一些概念,你不需要非常详细的知道具体的原理,但你需要有一个大概得概念。

前面说了,《程序的本质,就是计算机对信息的处理和输出》。想要机器运行程序,就要让机器理解你传递的信息。人们在设计电子机器的时候,通过大量的逻辑电路和控制单元,让机器实现了各种各样的功能。逻辑电路的实现过程虽然复杂,但你只需要明白它是通过物理手段控制电信号的运行。

我们用一个实际的灯泡电路来说明这个过程:假设我们有一块电路板,连接着一个灯泡和一个开关。每次你按下开关,灯泡就会亮起;松开开关,灯泡就会熄灭。我们称这个简单的装置为《灯泡控制器》。

你每次按下开关,就是向电路传递了一条信号;灯泡的亮起,就是电路根据信号做出的“输出”。我们可以将这个按下开关的动作定义为信号“1”,松开开关定义为信号“0”。通过这种方式,我们可以用一连串的“1”和“0”来控制灯泡的亮灭。

比如,现在我们按下开关一次,然后松开,再按下,再松开,重复四次。这个动作对应的信号是“1010”。

1(按下开关,灯泡亮起)

0(松开开关,灯泡熄灭)

1(再按下开关,灯泡再次亮起)

0(再松开开关,灯泡再次熄灭)。

这段“1010”的信号,就是一个最原始的程序。

现在,你可能会想:这个程序只控制了一个灯泡的亮灭,有什么用呢?

确实,单独控制一个灯泡看似作用不大。但如果我们扩展这个电路,增加更多的灯泡,比如用一个 8x8 的灯泡矩阵,那么我们就可以通过“1010”这样的信号组合控制每个灯泡的亮灭,让它们排列成一个简单的图案,比如“你好”两个字。

这其实就是现代 LED 显示屏的最基础原理。无数个看似独立的小灯泡,通过成千上万的“1”和“0”信号组合,显示出了你手机屏幕上的画面。

进一步,我们还可以在电路中加入更多的逻辑单元,让它们不仅能控制灯泡的亮灭,还能执行一些计算。比如某个单元接收到“110”信号后,会计算出结果“011”并传递给下一个单元。

如果将这些逻辑单元组合起来,就构成了一个更复杂的处理系统——这正是 CPU 的原理。CPU 本质上是一大堆逻辑电路单元的集合,通过不断处理我们输入的“1”和“0”信号,来控制不同的硬件执行任务。

而编程,就是用这些“1”和“0”信号来与机器对话,告诉它需要完成什么操作。虽然我们现在使用的是更高级的编程语言,比如 Python 或 JavaScript,但这些语言最终都会被翻译成计算机能够理解的“1”和“0”,再传递到硬件去执行。

好了你已经懂了编程原理了,现在你去写一个《原神》吧!

在《灯泡电路》中,我们通过简单的二进制代码 1010 控制灯泡闪烁一次:通电(1)、断电(0),如此循环。虽然这个过程能实现功能,但需要手动操作两根电线,效率极低。

计算机的早期历史:机器语言的诞生

在计算机发展的早期,人们对计算设备的需求并不复杂,主要是希望它们能够执行一些繁琐且耗时的计算任务。为了实现这些需求,开发者设计了一种直接与硬件交互的语言——机器语言

机器语言由 0 和 1 组成的指令集构成,能够被计算机硬件直接理解和执行。它代表了对机器逻辑最底层的控制。例如,执行基本的加法、减法,或对内存中的数据进行读取和清除等操作,都可以通过机器语言来实现。

从简单到复杂:指令集的优化

随着需求的增加,为了简化开发者的工作,不同的计算机设计者根据具体硬件需求开发了更高级的指令集。这些指令集在功能上进行了封装,比如:

• 基础算术操作(加减乘除)。

• 初始化数据类型、清除内存等组合性功能。

这些指令由多个底层的 0 和 1 组合而成,使得开发者无需直接编写每一步的二进制指令,从而提高了效率。然而,指令集本质上仍是由 0 和 1 组成,从人类的角度来看,理解和操作这些内容仍然非常复杂。

早期编程:手工输入机器语言

在计算机发展的初期,编程工作非常繁琐。程序员通常需要手动在草稿纸上写下完整的 0 和 1 机器语言代码,然后通过打孔纸带、拨动开关等方式,将这些指令输入到计算机中。以显示“HELLO WORLD”为例,如果是在早期的 x86 架构下,程序可能会像这样:

image.png

随着计算任务的复杂度不断提升,程序员逐渐意识到,直接使用 0 和 1 的机器语言编写程序变得越来越困难。机器语言不仅晦涩难懂,还极易出错。一旦程序出现问题,定位和修复的过程简直是一场噩梦。此外,不同厂商设计的计算机往往采用各自的 CPU 指令集,同样的功能可能需要完全不同的机器码来实现。这意味着更换硬件后,程序员不得不重新学习新的指令集,进一步增加了开发的复杂性。

为了解决这些问题,助记符应运而生。由于指令的功能是固定的,人们开始使用简短的单词或缩写来代替复杂的 0 和 1。程序员可以直接用助记符编写程序,而无需记忆具体的机器码。代码完成后,只需将助记符翻译为对应的机器码即可。这种方法不仅显著降低了编程的难度,还大幅提升了开发效率。同时,助记符更接近人类语言,使程序员能够更直观地理解自己的代码。即便程序出现错误,定位和解决问题也变得更加轻松。

助记符的使用在程序员之间迅速传播,并得到了广泛认可。短短时间内,这种开发方式从一种非正式的实践转变为主流工具,并逐步实现了标准化。随着这一过程的推进,以助记符为核心的编程方法进一步演化成一种更加贴近人类语言的编程方式,正式命名为“汇编语言”。

还是如上的问题,换成汇编语言,则可以写成:

image.png

在汇编语言中,例如 mov ax 对应的就是机器码 10111000。其中,mov 是英文单词 move 的缩写,而 ax 是累加器寄存器(Accumulator Register)的缩写(具体用途不必深入理解,在早期计算机中,AX 常用作运算的中间结果寄存器,相当于一个变量)。举例来说,mov ax, 0x1234 的字面意思就是将 0x1234 移动到 AX 寄存器中。

汇编语言的诞生极大地提高了编程效率,也使程序的复杂度得以大幅提升。然而,你或许会注意到一个问题:将汇编语言翻译成机器码仍然需要由人来手动完成。程序员此时扮演了翻译者的角色,这不仅效率低下,而且容易出错。对于专注于效率的程序员来说,这是不可容忍的。

正因如此,让我们再次回顾那句经典的话—— “程序的本质,就是计算机对信息的处理和输出。” 为了实现更高程度的自动化,程序员们开发了一种能够自动将汇编语言翻译成机器码的工具,称为“汇编器”。汇编器不仅能将汇编语言逐一对应地翻译成机器语言,还提供了进一步简化编程的功能。开发者将一系列常用的指令组合在一起,抽象为单个或少量的汇编命令,再由汇编器生成对应的机器码。这种设计极大地提升了编程效率,使机器语言与人类语言的差距进一步缩小。这一发展过程十分迅速,仅用了几年时间,汇编语言便走向成熟。

汇编语言的诞生,不仅解放了程序员的双手,还推动了计算机向更广阔的应用领域迈进。从最初的灯泡电路到如今复杂的 3D 游戏,我们依然能感受到这些助记符背后所体现的简化与智慧。这是人类技术发展的一个重要跃迁,它让计算机真正开始服务于人类,而不仅仅局限于基础的逻辑操作。

开启《大套娃时代》

随着计算机技术的飞速发展,编程方式也在不断演进。尽管汇编语言极大地简化了与硬件的交互,但程序员仍需要直接操作底层硬件。这种方式虽然灵活,但效率低下,尤其在面对大量重复性操作时更显得力不从心。为了解决这一问题,程序员们开始尝试将一些基础且通用的底层功能(如文件管理、任务调度、用户交互等)进行整合,从而逐步实现对底层操作的“自动化”。这一探索最终催生了操作系统的诞生。

操作系统可以看作是由一组基础程序组成的集合,专门用于简化对计算机的操作。它屏蔽了硬件的复杂性,为程序员提供了一套标准化的工具和接口。举例来说,在没有操作系统的时代,开发一个简单的计算器程序可能需要手动编写用户输入处理程序、显示器交互程序,以及其他底层配套功能。每次开发都得从零开始,既耗时又低效。

而有了操作系统后,这些基础功能已经被预先实现并优化。程序员可以直接调用操作系统提供的功能模块(如输入/输出接口、文件管理接口等),轻松处理用户输入或将结果显示在屏幕上。这样,开发者可以专注于计算器的核心业务逻辑(如加减乘除运算),而无需再花费精力处理底层硬件的复杂操作。

操作系统的诞生,不仅显著提升了开发效率,也为计算机应用的发展奠定了基础。它推动软件开发迈向抽象化模块化,为更高级的编程语言的出现创造了理想的环境。

高级语言的诞生

随着现代操作系统的普及,汇编语言因过于接近底层硬件,逐渐不再适合开发复杂的应用程序和操作系统。为了解决这一问题,程序员们开始追求更加简洁、高效的编程方式,于是高级语言应运而生。

高级语言的出现如雨后春笋,其中的一个里程碑便是C语言。高级语言在设计思路上,与机器语言进化为汇编语言的过程有些类似:它通过编译器将源代码翻译为汇编语言,再由汇编器将其转为机器语言。其他高级语言也沿用了类似的“分层翻译”模式,通过编译器或解释器将高层次的指令逐步转化为底层能够直接执行的代码。

这种分层设计让开发者可以专注于更高层次的逻辑和功能,而无需了解底层实现的复杂细节。分层翻译的思想,不仅提升了编程效率,也促进了编程语言的快速发展,使计算机系统能够适应越来越复杂的应用需求。

高级语言的本质,就是为了简化编程,帮助开发者专注于业务逻辑。不同的高级语言在不同的时代、场景、需求和技术目标下诞生,但它们都有一个共同特点:最终都会被翻译为机器语言执行。而这种翻译需要运行在对应的“环境”上,也就是高级语言的程序必须在能够“理解”其语法的平台中执行。

高级语言还提供了庞大的、经过精心设计的内置程序库。这些库将许多复杂且基础的操作抽象并封装,大大简化了开发流程,让程序员能够专注于核心业务逻辑,而无需为底层实现细节操心。

从“基础”到“现代”的跃迁

现代编程的每一次发展都离不开一代又一代程序员的努力与积累。从最初直接操作硬件,到构建复杂的软件框架,每一个看似简单的功能背后,都站立着无数前辈程序员的智慧与心血。例如,当你用一门高级语言打印一行“HELLO WORLD”时,背后其实依赖了大量底层程序,从字符编码处理到屏幕输出的硬件控制,都是前人辛勤劳动的结晶。

现代编程的魅力,正是它让我们能够站在巨人的肩膀上,直接调用那些经过精心设计的基础程序,不断突破技术的边界。

序章总结

通过序章的内容,我们简单梳理了“编程”的本质和发展,最终可以用两句话总结:

  1. 程序的本质:计算机对信息的处理和输出。

  2. 现代编程的核心:建立在无数现有的基础程序之上,高级语言的存在,就是简化你对这些基础程序的调用,而不必直接操作机器。