程序和编程语言介绍

现代计算机的速度非常快,并且一直在变得更快。然而,计算机也有一些显著的限制:它们只能理解有限的指令集,并且必须被精确地告知要做什么。 计算机程序是一系列指令,指导计算机按照指定的顺序执行某些操作。计算机程序通常用编程语言编写,这是一种旨在便于编写计算机指令的语言。有许多不同的编程语言可供选择,每种语言都满足不同的需求。编写程序的行为(和艺术)被称为编程。我们将在本章后续的课程中更具体地讨论如何用C++创建程序。

当计算机执行程序中的指令所描述的操作时,我们说它正在运行或执行程序。计算机不会开始执行程序,直到被告知这样做。这通常需要用户启动(或运行或执行)程序,尽管程序也可以由其他程序启动。

硬件与软件的关系

程序在计算机的硬件上执行,硬件包括构成计算机的物理组件。典型计算设备上的显著硬件包括:

CPU(中央处理单元,通常被称为计算机的"大脑"),它实际执行指令。

内存,计算机程序在执行前被加载到这里。

交互设备(例如显示器、触摸屏、键盘或鼠标),允许人与计算机交互。

存储设备(例如硬盘、SSD或闪存),即使在计算机关闭时也能保留信息(包括已安装的程序)。

相比之下,软件这个术语广义上指的是系统上设计为在硬件上执行的程序。

平台与可移植性

在现代计算中,程序通常不仅与硬件交互——它们还与系统上的其他软件(特别是操作系统)交互。平台这个术语指的是一组兼容的硬件和软件(操作系统、浏览器等),为软件运行提供环境。例如,“PC"这个术语通常被用来指代由Windows操作系统在x86系列CPU上运行的平台。

平台通常为在其上运行的程序提供有用的服务。例如,桌面应用程序可能会请求操作系统为其分配一块空闲内存,在那里创建一个文件,或播放声音。运行中的程序不需要知道这是如何实际实现的。如果程序使用平台提供的功能或服务,它就会依赖于该平台,并且如果不进行修改,就不能在其他平台上运行。一个可以轻松从一个平台转移到另一个平台的程序被称为可移植的。修改程序使其在不同平台上运行的行为被称为移植。

现在我们已经讨论了程序,让我们讨论编程语言。

机器语言:计算机的原始语言

计算机的CPU无法理解C++。相反,CPU只能处理用机器语言(或机器代码)编写的指令。给定CPU能理解的所有可能的机器语言指令集称为指令集。

这是一个机器语言指令的示例:10110000 01100001。

每条指令都被CPU解释为执行一个非常具体的工作命令,例如"比较这两个数字"或"将这个数字复制到那个内存位置”。在计算机刚被发明的时候,程序员不得不直接用机器语言编写程序,这是一件非常困难和耗时的事情。

这些指令如何组织和解释超出了本教程系列的范围,但值得指出两点。

首先,每条指令由1和0的序列组成。每个单独的0或1称为二进制数字,或简称位。机器语言指令中的位数各不相同——例如,一些CPU处理的指令总是32位长,而另一些CPU(如您可能使用的x86系列)的指令可以有可变长度。

其次,每个兼容的CPU系列(例如x86、Arm64)都有自己的机器语言,这种机器语言与其它CPU系列的机器语言不兼容。这意味着为一个CPU系列编写的机器语言程序不能在不同系列的CPU上运行!

相关内容

“CPU系列"正式称为"指令集架构”(简称"ISA")。维基百科上有不同CPU系列的列表。

汇编语言:人类可读的第一步

由于机器语言对人类来说难以阅读和理解,因此发明了汇编语言。在汇编语言中(通常简称为汇编),每条指令都由一个简短的缩写标识(而不是一组位),并且可以使用名称和其他数字。

这是上述相同指令在x86汇编语言中的表示:mov al, 061h。

顺便说一句… mov是一个x86汇编指令,将一个值复制到某个位置。在这种情况下,值061h将被复制到al CPU寄存器(CPU本身的一部分内存)中。

这使得汇编语言比机器语言更容易阅读和编写。用汇编语言编写的程序往往非常快,当速度至关重要(或在资源严重受限的环境中)时,汇编语言仍然被使用。

然而,由于CPU只能讲机器语言,因此在计算机执行汇编程序之前,必须将其翻译成机器语言。这是通过使用一个称为汇编器的程序完成的,它接受汇编源代码作为输入,并输出包含机器语言指令的程序。

就像每个CPU系列都有自己的机器语言一样,每个CPU系列也有自己的汇编语言,这种汇编语言被设计为可以被汇编成同一CPU系列的机器语言。这意味着有许多不同的汇编语言,每种都有自己的独特语法和指令,尽管它们在概念上是相似的。

低级语言的优缺点

机器语言和汇编语言被认为是低级语言,因为这些语言提供了最小的架构抽象。换句话说,编程语言本身是针对它将运行的特定指令集架构量身定制的。

低级语言有一些显著的缺点:

用低级语言编写的程序不可移植。由于低级语言针对ISA,用该语言编写的程序也是如此。将这类程序移植到其他架构通常是非平凡的。

用低级语言编写程序需要详细了解架构本身。例如,指令mov al, 061h需要知道al指的是这个特定平台上可用的CPU寄存器,并了解如何使用该寄存器。在不同的架构上,这个寄存器可能有不同的名称,有不同的限制,或者根本不存在。

低级程序难以理解。虽然单个汇编指令可以很容易理解,但很难推断出一段汇编代码实际上在做什么。由于汇编程序需要许多指令来执行即使是简单的任务,它们往往相当长。

低级语言的主要好处是它们速度快。当代码部分对性能至关重要时,仍然使用汇编语言。它还在一些其他情况下使用,我们将在稍后讨论其中之一。

高级语言:现代编程的基础

为了解决低级语言的理解和可移植性问题,开发了新的"高级"编程语言,如C、C++、Pascal(以及后来的语言,如Java、Javascript和Perl)。

这是上述相同指令在C/C++中的表示:a = 97;。

就像汇编程序(必须被汇编成机器语言)一样,用高级语言编写的程序在可以运行之前必须被翻译成机器语言。这主要有两种方式:编译和解释。

C++程序通常被编译。编译器是一个程序(或程序集合),它读取一种语言的源代码(通常是高级语言),并将其翻译成另一种语言(通常是低级语言)。例如,C++编译器将C++源代码翻译成机器代码。

可选阅读

大多数C++编译器也可以配置为生成汇编代码。当程序员想要查看编译器为程序的某一部分生成了哪些具体指令时,这很有用。

编译器输出的机器代码然后可以被打包成一个可执行文件(包含机器语言指令),可以分发给其他人,并由操作系统启动。值得注意的是,运行可执行文件不需要安装编译器。

最初,编译器是原始的,产生的汇编或机器代码速度慢且未优化。然而,多年来,编译器已经变得非常擅长产生快速、优化的代码,在某些情况下,它们可以比人类做得更好!

这是一个简化的编译过程表示:

或者,解释器是一个程序,它直接执行源代码中的指令,而不需要先进行编译。解释器往往比编译器更灵活,但在运行程序时效率较低,因为每次运行程序时都需要进行解释。这也意味着解释器必须安装在每台将运行解释程序的机器上。

这是一个简化的解释过程表示:

可选阅读

这里可以找到编译器与解释器优势的比较。

编译程序的另一个优势是,分发编译程序不需要分发源代码。在非开源环境中,这对知识产权(IP)保护很重要。

大多数高级语言可以被编译或解释。传统上,像C、C++和Pascal这样的高级语言被编译,而像Perl和Javascript这样的"脚本"语言则倾向于被解释。有些语言,如Java,使用两者的混合。我们很快就会更详细地探讨C++编译器。

高级语言的优势

高级语言之所以被称为高级,是因为它们提供了对底层架构的高级抽象。

考虑指令a = 97;。这条指令让我们可以在内存中的某个地方存储值97,而不需要知道这个值将被放置在哪里,或者CPU需要什么特定的机器代码指令来存储这个值。实际上,这条指令完全没有平台特定的内容。编译器做了所有工作,以确定这个C++指令如何翻译成特定平台的机器代码。

高级语言允许程序员在不了解它将运行的平台的情况下编写程序。这不仅使程序更容易编写,而且使它们更具可移植性。如果我们小心,我们可以编写一个单一的C++,它将在每个有C++编译器的平台上编译!一个设计为在多个平台上运行的程序被称为跨平台。

对于高级读者

以下是可能阻碍您的C++代码可移植性的部分列表:

许多操作系统,如Microsoft Windows,提供您可以在代码中使用的特定平台功能。这些可以使为特定操作系统编写程序变得更容易,或提供与该操作系统的更深层次集成。

许多第三方库只在某些平台上可用。如果您使用其中之一,您将被限制在该库支持的平台。

一些编译器支持特定于编译器的扩展,这些功能只在该编译器中可用。如果您使用这些,您的程序将无法在不支持相同扩展的其他编译器上编译,除非进行修改。我们将在您安装编译器后进一步讨论这些。

在某些情况下,C++语言允许编译器确定某事物的行为方式。我们在第1.6课——未初始化变量和未定义行为下进一步讨论"实现定义行为"。

如果您只针对单一平台,那么可移植性可能不是那么重要。但如今许多应用程序都针对多个平台,以扩大它们的影响力。例如,移动应用程序可能希望同时针对iOS和Android。

即使最初看起来可移植性似乎没用,许多最初针对单一平台(例如PC)的应用程序在取得一定成功后,决定移植到其他平台(例如Mac和各种控制台)。如果您没有从一开始就考虑可移植性,那么后来移植您的应用程序将需要更多的工作。

在这些教程中,我们将尽可能避免特定平台的代码,以便我们的程序可以在任何有现代C++编译器的平台上运行。

高级语言还有其他好处:

用高级语言编写的程序更容易阅读、编写和学习,因为它们的指令更接近我们每天使用的自然语言和数学。在许多情况下,高级语言需要更少的指令来执行与低级语言相同的任务。例如,在C++中,您可以在一行中编写a = b * 2 + 5;。在汇编语言中,这将需要4到6条不同的指令。这使得使用高级语言编写的程序更加简洁,更容易理解。

高级语言通常包括额外的功能,使执行常见编程任务变得更容易,例如请求一块内存或操作文本。例如,只需一条指令就可以确定字符"abc"是否存在于一大段文本中(如果存在,需要检查多少个字符直到找到"abc")。这可以显著降低复杂性和开发时间。

术语

尽管C++在技术上被认为是高级语言,但更新的编程语言(例如脚本语言)提供了更高级别的抽象。因此,C++有时被不准确地称为"低级语言",与之相比。

作者注

今天,C++可能更准确地被描述为中级语言。然而,这也突出了C++的一个关键优势:它通常提供了在不同抽象级别上工作的能力。您可以选择在较低级别上操作以获得更好的性能和精度,或在较高级别上操作以获得更大的便利性和简单性。

规则、最佳实践和警告

在这些教程中,我们将在以下三个类别下突出许多重要点:

规则

规则是您必须执行的指令,因为语言要求这样做。不遵守规则通常会导致您的程序无法工作。

最佳实践

最佳实践是您应该做的事情,因为这样做的方式要么是传统的(惯用的),要么是推荐的。也就是说,要么每个人都以这种方式做事(如果您不这样做,您将做一些人们不期望的事情),或者它通常比替代方案更优越。

警告

警告是您不应该做的事情,因为它们通常会导致意外的结果。

关注公众号,回复"cpp-tutorial"

可领取价值199元的C++学习资料

公众号二维码

扫描上方二维码或搜索"cpp-tutorial"