为什么编程语言千变万化?理解其分类与核心要素

一、引言二、程序设计语言的基本概念2.1 低级语言与高级语言2.2 编译与解释2.3 程序设计语言的构成要素

三、程序设计语言的分类3.1 程序设计语言发展概况3.2、程序设计语言的分类

四、程序设计语言的基本成分4.1 数据成分4.2 运算成分与控制成分运算成分控制成分

4.3 传输成分与函数

五、总结

一、引言

程序设计语言是一种为书写计算机程序而设计的人工符号语言,其核心功能在于描述、组织和逻辑推导计算过程。现代程序设计语言的广泛应用始于 20 世纪 50 年代末,特别是 1957 年出现的 FORTRAN 语言。程序设计语言的发展历程是一个持续演进的过程,其根本驱动力在于追求更高的抽象机制和对程序设计思想更良好的支持。

本文旨在介绍程序设计语言的基本概念、主要组成部分以及若干具有代表性的程序设计语言。

二、程序设计语言的基本概念

2.1 低级语言与高级语言

计算机硬件能够直接执行的指令序列是由二进制(0 和 1)代码组成的,即机器指令程序。机器指令是计算机能够理解的最基础语言。由于机器指令是特定计算机系统固有的、面向硬件的语言,使用机器语言进行程序设计不仅效率低下,而且程序难以阅读、修改和维护。

为了提高可读性和编写效率,人们引入了符号来代替二进制机器指令,例如使用 ADD 表示加法、SUB 表示减法等。这些用符号表示的指令称为汇编指令,由汇编指令构成的语言称为汇编语言。汇编语言与机器语言紧密对应,其语法和结构在很大程度上仍然取决于特定的计算机硬件指令集,因此它仍被视为一种面向机器的低级语言。

在此基础上,为了进一步提升程序设计的效率和抽象层次,人们开发了功能更强大、更接近人类自然语言的程序设计语言,统称为高级语言。常见的高级语言包括 Java、C、C++、Python、PHP、Delphi、Pascal 等。高级语言使得程序员能够更专注于问题本身的逻辑,而不是底层硬件细节,极大地提高了程序设计的效率和可移植性。

2.2 编译与解释

计算机只能直接理解机器语言,因此使用高级语言或汇编语言编写的程序(称为源程序)需要通过特定的“语言处理程序”翻译成机器语言才能在计算机上执行。主要的翻译方式包括汇编、解释和编译。

汇编语言源程序需要通过汇编程序翻译成目标程序(机器码)后执行。高级语言源程序则需要对应的解释程序或编译程序进行翻译和执行。

解释程序(解释器): 解释器或者直接逐条读取并执行源程序中的指令,或者先将源程序翻译成某种中间表示形式再执行。在解释执行过程中,解释程序和源程序(或其中间表示)始终参与程序的运行,程序的控制权在解释器手中。解释执行的特点是不生成独立于翻译过程的目标程序。

编译程序(编译器): 编译器将整个源程序一次性翻译成与源程序功能等价的目标程序(通常是机器码或特定平台的字节码)。翻译完成后,计算机直接运行生成的目标程序,源程序和编译器不再参与程序的执行过程。编译执行的特点是生成可以独立保存和执行的目标程序。

简单来说,编译方式下,翻译发生在程序运行之前,生成一个可独立执行的文件;而解释方式下,翻译与执行交替进行,每次执行都需要解释器的参与。

2.3 程序设计语言的构成要素

通常,对程序设计语言的定义涉及以下几个核心要素:语法、语义和语用。

语法 (Syntax): 定义了如何用语言的基本符号来构成程序中的各种有效成分(如单词、表达式、语句、函数、整个程序等)的一组规则。语法规则通常分为两部分:

词法规则 (Lexical Rules): 规定如何由基本字符组成具有独立意义的最小单位,即词法记号(Token,如关键字、标识符、常量、运算符等)。语法规则 (Grammatical Rules): 规定如何将词法记号组合成符合语言结构的语法成分。程序设计语言的语法常常使用形式语言理论(如上下文无关文法)进行精确描述。 语义 (Semantics): 规定了符合语法规则的各个语言成分所代表的意义或计算行为。语义可以进一步分为:

静态语义 (Static Semantics): 指在程序运行之前(通常在编译阶段)可以确定的语言成分的含义或属性,例如类型检查、变量声明的合法性等。动态语义 (Dynamic Semantics): 指在程序执行过程中才能确定的语言成分的含义或行为,即程序运行时会发生什么。一个程序的最终执行效果完整地体现了该程序的动态语义,它取决于构成程序各个部分的语义以及它们的组合方式。 语用 (Pragmatics): 描述了语言符号与使用者之间的关系,涉及语言的设计背景、使用习惯、实现技术以及对用户和环境的影响。语用关注的是语言在实际应用中的上下文和效果。

此外,语言的实现也涉及其“语境”(Context),即理解和执行程序设计语言所需的环境,这包括用于翻译的编译/解释环境和程序实际运行的执行环境。

三、程序设计语言的分类

程序设计语言承载着算法表达与计算机实现的双重目标。当前,程序设计语言种类繁多,且在应用领域上各有侧重。通常,若一种程序设计语言的设计不依赖于特定的机器硬件,强调更高的抽象层次,则称其为高级语言。反之,直接面向硬件指令的语言(如机器语言和汇编语言)则称为低级语言。如果一种程序设计语言能够有效地应用于广泛的问题求解场景,则称其为通用程序设计语言。

3.1 程序设计语言发展概况

程序设计语言领域是一个持续演进和不断创新的过程。各种现有语言在不断完善和更新,同时新的语言也层出不穷,并且在相关的开发工具方面,组件化和可视化技术取得了显著进展,极大地提升了开发效率。

以下简要介绍一些在程序设计语言发展史上具有重要地位或当前仍广泛应用的代表性语言:

Fortran (Formula Translation) Fortran 是第一个被广泛应用于科学和工程计算领域的高级程序设计语言,诞生于 20 世纪 50 年代。一个 Fortran 程序通常由一个主程序和若干子程序(或称为模块)构成。该语言因其贴近数学公式的自然表达方式和极高的执行效率,特别是在数值计算领域积累了大量成熟可靠的代码库,至今仍广泛应用于并行计算和高性能计算(HPC)领域。

ALGOL (Algorithmic Language) ALGOL 语言出现在晶体管计算机时代,其中 Algol 60 是程序设计语言发展史上的一个重要里程碑。它对 20 世纪 60 年代的程序语言设计产生了深远影响,并为后续软件自动化和提高软件可靠性奠定了理论基础。Algol 60 首次引入了严格的、形式化的语法描述方法——巴科斯范式(BNF),并引入了局部性概念、动态存储分配以及递归等重要的程序设计概念。

Pascal Pascal 是一种由 Niklaus Wirth 教授于 1970 年设计的过程式、结构化程序设计语言。它源自 ALGOL 60,但在功能和易用性上有所增强。Pascal 语言曾长期在高校计算机科学教育中占据主导地位,其集成开发环境 Turbo Pascal 曾非常流行。1985 年发布的 Object Pascal 版本则将其扩展为一种支持面向对象特性的语言。

C 语言 C 语言是 Dennis Ritchie 在 20 世纪 70 年代初设计的一种通用程序设计语言。它是 UNIX 操作系统及其上大量软件的主要开发语言。C 语言巧妙地结合了高级语言的抽象能力和汇编语言对底层硬件的控制能力,提供了丰富的运算符和紧凑的语句格式。凭借其高效的执行性能以及允许直接访问内存和进行系统级操作的能力,C 语言成为系统编程和实时处理应用开发中的核心语言。

C++ C++ 是 Bjarne Stroustrup 在 20 世纪 80 年代基于 C 语言发展而来的。它在保持与 C 语言兼容性的同时,引入了类、继承、多态等面向对象特性,以及模板、异常处理等机制,极大地增强了语言的抽象和组织能力,成为一种强大的面向对象程序设计语言,广泛应用于系统软件、应用软件、游戏开发等领域。

C# (C Sharp) C# 是由 Microsoft 公司开发的一种面向对象的、运行于 .NET Framework (或 .NET) 平台上的高级程序设计语言。相较于 C++,C# 在安全性(如自动垃圾回收)、易用性等方面进行了许多改进和增强,是开发 Windows 应用程序、Web 应用、移动应用以及游戏等领域的常用语言。

Objective-C Objective-C 是基于 C 语言扩展而来的面向对象编程语言。它继承了 C 语言的所有特性,并加入了 Smalltalk 风格的消息传递机制来实现面向对象。Objective-C 曾是 Apple macOS 和 iOS 平台主要的应用程序开发语言(现已被 Swift 语言部分取代),其语言风格与其他主流语言有所差异。它支持单一父类继承。

Java Java 语言由 Sun Microsystems(现为 Oracle)于 20 世纪 90 年代初推出。它最初旨在用于开发网络浏览器中的小型应用程序(Applets),但很快发展成为一种通用、跨平台的程序设计语言。Java 保留了 C++ 的基本语法、类和继承等概念,同时摒弃了 C++ 中一些复杂或易出错的特性,使得语言更加简洁、健壮且易于学习。Java 的核心特点是“一次编写,随处运行”(Write Once, Run Anywhere, WORA),这得益于其在 Java 虚拟机(JVM)上运行的字节码机制,使其在企业级应用、移动开发(尤其是 Android)和 Web 后端等领域得到极其广泛的应用。

Ruby Ruby 是由松本行弘(Yukihiro Matsumoto)于 1993 年左右设计的解释型、面向对象、动态类型脚本语言。Ruby 的核心理念是“一切皆对象”,包括基本数据类型。它强调简洁优雅的语法,提高了开发效率,常用于 Web 开发(特别是 Ruby on Rails 框架)和脚本编写。

PHP (Hypertext Preprocessor) PHP 是一种主要运行于服务器端的、嵌入 HTML 文档的脚本语言。其语法风格类似于 C 语言,专门为 Web 开发而设计。PHP 能够快速生成动态网页内容,支持多种数据库和操作系统,是构建 Web 应用程序,特别是内容管理系统(CMS)和电子商务平台的常用语言。

Python Python 是一种由 Guido van Rossum 设计的、强调代码可读性和简洁语法的解释型、面向对象的动态类型程序设计语言。Python 可以用于编写独立的应用程序、快速脚本,也适合构建复杂应用的早期原型。它支持对操作系统的底层访问,可以将源程序编译成字节码在 Python 虚拟机上运行。Python 核心简洁但功能强大,拥有庞大的标准库和第三方库生态系统,且易于用 C/C++/Java 等语言进行扩展,因此被广泛应用于 Web 开发、数据科学、人工智能、自动化脚本、科学计算等几乎所有软件开发领域。

JavaScript JavaScript 是一种主要运行在客户端浏览器中的脚本语言(通过 Node.js 也可用于服务器端)。它被广泛应用于 Web 开发,用于为网页添加动态功能、实现交互效果,提升用户体验。JavaScript 通常直接嵌入在 HTML 页面中执行,与 HTML 和 CSS 共同构成了现代 Web 前端开发的核心技术栈。

Delphi Delphi 是一款经典的 Windows 环境下的可视化快速应用开发工具(其 Linux 版本为 Kylix)。它使用基于 Object Pascal 语言和面向构件的开发框架,提供了高效的编译器、强大的数据库支持以及与 Windows API 的紧密集成,以其快速构建桌面应用程序的能力而著称。

Visual Basic .NET (VB.NET) Visual Basic .NET 是 Microsoft .NET Framework (或 .NET) 平台上的主要编程语言之一,是一种面向对象的语言。使用 VB.NET 等 .NET 语言编写的源代码不会直接编译成本地机器码,而是先编译成一种中间代码——Microsoft Intermediate Language (MSIL)。MSIL 在程序执行时,通过 .NET Framework 的通用语言运行时(CLR)被即时编译(JIT)成本地机器码执行。因此,运行 VB.NET 程序需要目标计算机上安装有兼容的 .NET Framework 或 .NET 运行时环境。

程序设计语言的技术和生态持续发展,新的语言和开发范式不断涌现,共同推动着软件开发效率和应用能力的提升。

3.2、程序设计语言的分类

程序设计语言旨在实现算法的表达与计算机的执行。当前存在的程序设计语言种类繁多,它们在设计理念和适用领域上各有侧重。虽然没有统一的标准分类体系,但根据其核心的设计思想和程序组织方式,可以将程序设计语言划分为不同的编程范式(Programming Paradigms)。

程序设计语言大致归类为以下几种主要的编程范式:命令式与结构化程序设计、面向对象程序设计、函数式程序设计以及逻辑程序设计等。

(1)命令式与结构化程序设计。

命令式程序设计语言(Imperative Programming Languages) 是基于操作或动作序列的语言。在这类语言中,计算过程被看作是一系列改变程序状态(如变量的值)的命令或语句的执行。命令式编程是最早出现的编程范式之一,其思想直接来源于计算机硬件指令的执行方式。Fortran 是早期的命令式语言代表,而 Pascal 和 C 语言也充分体现了命令式程序设计的关键思想。

结构化程序设计(Structured Programming) 可以视为命令式程序设计的一种重要方法论和实践规范。它强调通过使用有限的、规范的控制结构(如顺序、选择/分支和循环/迭代)来组织程序流程,并且每种结构都遵循单入口和单出口原则。结构化程序设计旨在提高代码的清晰度、可读性、可维护性和可靠性,通常结合模块化(将程序分解为独立的子程序或模块)和自顶向下逐步细化的设计方法。通过这些技术,结构化程序具有清晰简单的结构和较高的模块性,其描述方式更接近人们习惯的逻辑推理,显著提升了软件质量。尽管新的范式不断涌现,结构化程序设计思想及其技术至今仍广泛应用于许多程序的开发中。C、Pascal 等语言是支持和鼓励结构化程序设计的典型代表。

(2)面向对象程序设计。

面向对象程序设计(Object-Oriented Programming, OOP) 是程序设计语言在抽象层次不断提高过程中的重要发展。从早期的机器语言、汇编语言,到结构化高级语言,再到面向对象语言,反映了软件开发从关注具体执行步骤转向关注现实世界概念的抽象和模型化。

面向对象编程的核心思想是将数据及其操作方法封装在一起,形成称为“对象”的基本单元。这种思想在很大程度上起源于模拟领域的 Simula 语言,该语言首次提出了对象和类的概念。C++、Java 和 Smalltalk 是面向对象程序设计语言的典型代表。面向对象语言通常必须支持一系列核心特性,包括:

封装(Encapsulation): 将数据和操作数据的方法捆绑在一起,对外隐藏内部实现细节。抽象(Abstraction): 关注对象的本质特征和行为,忽略不重要的细节。继承(Inheritance): 允许基于现有类创建新的类(子类),子类可以继承父类的属性和方法,实现代码复用和扩展。多态(Polymorphism): 允许不同类的对象对同一消息(方法调用)作出不同的响应,提高了程序的灵活性。

这些特性共同使得面向对象编程成为构建复杂、可维护和可重用软件系统的主流范式之一。

(3)函数式程序设计。

函数式程序设计语言以数学上的 Lambda 演算(Lambda Calculus)为理论基础。其基本概念源于 LISP 语言,LISP 是在 1958 年为人工智能应用而设计的,被认为是第一种函数式语言。

函数式编程将计算视为数学函数的求值过程。它强调使用纯函数(Pure Functions),即函数的输出只依赖于其输入参数,并且没有副作用(不改变程序状态或执行其他可观察的操作)。程序由函数的定义和组合构成,通过函数的应用(调用)来完成计算。递归是函数式编程中常用的控制结构。

函数式程序设计的一个主要优点是引用透明性(Referential Transparency):表达式的值只由其自身决定,不受外部状态影响。这意味着一个函数调用可以被其计算结果直接替换,而程序的行为不变。这有助于提高代码的可理解性、可测试性,并天然支持并行计算。

LISP 语言在许多方面与其他语言不同,其中最显著的特点之一是其程序和数据的形式是等价的(基于列表结构),这使得程序可以像数据一样被处理,或者数据结构可以被执行,为元编程(Metaprogramming)提供了便利。常见的函数式语言或强烈支持函数式范式的语言包括 Haskell、Scheme、Clojure、Erlang,以及 Scala 等支持多范式的语言。

(4)逻辑程序设计。

逻辑程序设计语言(Logic Programming Languages) 是一类基于形式逻辑的语言,特别是建立在关系理论和一阶谓词逻辑之上。PROLOG(Programming in Logic)是该范式最具代表性的语言。

在逻辑程序设计中,程序并非一系列指令,而是一组 事实(Facts) 和规则(Rules)的集合,这些事实和规则共同描述了问题领域的知识和关系。程序的执行过程是通过对这个知识库进行查询(Query)来触发的。系统会尝试利用已有的事实和规则,通过统一(Unification)和回溯(Backtracking) 等机制,运用逻辑推理来寻找满足查询的解答。

逻辑程序设计提供了一种完全不同的声明式编程风格,开发者关注的是“问题是什么”,而不是“如何解决问题”。PROLOG 在处理符号计算、进行复杂逻辑推理和解决约束满足问题方面非常强大,特别适用于人工智能领域的应用,如专家系统、自然语言理解、自动定理证明以及数据库查询等。

四、程序设计语言的基本成分

任何程序设计语言,无论其范式或应用领域如何,都包含一系列基本成分,这些成分共同构成了表达计算过程的语法和语义基础。这些基本成分通常涵盖了如何表示数据、如何操作数据、如何控制程序执行流程以及如何在程序的不同部分之间传输信息。我们可以将程序设计语言的基本成分归纳为:数据成分、运算成分、控制成分和传输成分。

4.1 数据成分

程序设计语言的数据成分主要体现在其数据类型(Data Types)体系上。数据类型是用于对程序中各种可能出现的数据对象(Data Objects)进行分类的机制。数据对象通常对应于应用系统中具有特定意义的实体或值。数据类型不仅规定了某个数据对象可能具有的值的集合,还定义了这些值在计算机内部的表示方式(即内存布局)以及可以对其执行的合法操作集。通过数据类型,编译器可以在程序编译阶段检查表达式中操作的合法性,从而提高程序的健壮性。

在程序中,数据是程序操作的对象,它们在内存中占据一定的空间,并具有一系列重要的属性:

名称(Name): 数据对象在程序中通过**标识符(Identifier)**来命名,标识符通常由字母、数字和下划线组成,是程序中引用数据对象的方式。类型(Type): 前文所述的数据类型,决定了数据占用内存的大小、存储形式、值的范围以及可进行的操作。存储类别(Storage Class): 决定了数据对象在内存中的存放位置(如栈、堆、静态存储区)以及它的生存期(Lifetime)。作用域(Scope): 规定了数据对象名称在程序源代码中有效的区域范围,即可以在哪些地方通过其名称访问该数据对象。生存期(Lifetime): 描述了数据对象从被分配内存空间到被释放内存空间的时间段。

数据对象可以从不同的角度进行分类。

按值的可变性:常量与变量。

变量(Variable): 在程序运行时,其值(内容)可以被改变的数据对象。变量具有左值(lvalue)和右值(rvalue)。左值指代数据对象在内存中的位置或身份(如地址),右值指代存储在该位置上的值(内容)。变量既有位置(左值),其内容(右值)也可以在程序执行过程中发生变化。常量(Constant): 在程序运行时,其值不能被改变的数据对象。常量通常只有右值(或一个不可变的左值),其内容在定义后保持不变。

按作用域:全局量与局部量。

全局变量(Global Variable): 其作用域通常覆盖程序的整个文件或多个文件。全局变量的存储空间通常在程序启动时分配,并在整个程序运行期间保持不变(静态分配),生存期与程序相同。局部变量(Local Variable): 其作用域限定在定义它的函数、代码块或特定结构内部。局部变量的存储空间通常在进入其作用域时分配,并在退出作用域时自动释放(动态或栈式分配),生存期与所在的作用域绑定。

按组织形式:数据类型分类。 程序设计语言提供了多种组织和表示数据的方式,通常可分为以下几类:

基本类型(Primitive/Basic Types): 语言预定义的最基本的数据类型,通常直接映射到机器硬件的数据表示,如整型(integer)、浮点型(floating-point)、字符型(character)、布尔型(boolean)等。

用户定义类型(User-Defined Types): 允许程序员基于语言提供的机制创建新的数据类型,如枚举类型(enum)。

构造类型(Constructed/Aggregate Types): 通过组合其他类型来构成的数据类型,如数组(Array,同类型元素的集合)、结构体(Struct,不同类型元素的集合)、联合体(Union,在同一内存空间存储不同类型的值)等。

指针类型(Pointer Types): 其值是内存地址的数据类型,用于直接访问内存或构建复杂的数据结构。

抽象数据类型(Abstract Data Types, ADT)/类类型(Class Types): 在面向对象语言中引入,将数据(属性)及其操作(方法)封装在一起,提供了更高层次的抽象和模块化能力。

(以 C/C++ 语言为例,其数据类型体系涵盖了上述大部分分类,其中布尔类型 (bool) 和类类型 (class) 是 C++ 在 C 的基础上新增的。)

4.2 运算成分与控制成分

运算成分

程序设计语言的运算成分规定了语言允许使用的运算符(Operators)及其运算规则(Operational Rules)。这些运算符用于对数据进行各种计算和处理。

大多数高级程序设计语言提供了以下基本运算类型:

算术运算(Arithmetic Operations): 用于数值计算,如加、减、乘、除、取模等。关系运算(Relational Operations): 用于比较两个值之间的关系,结果通常为布尔值(真或假),如大于、小于、等于、不等于等。逻辑运算(Logical Operations): 用于对布尔值进行逻辑组合或取反,如逻辑与(AND)、逻辑或(OR)、逻辑非(NOT)等。位运算(Bitwise Operations): 直接对数据在内存中的二进制位进行操作,如按位与、按位或、按位非、左移、右移等(某些语言支持,如 C/C++)。

运算符的使用严格依赖于操作数的数据类型。为了消除表达式求值的歧义,语言还规定了运算符的优先级(Precedence)和结合性(Associativity),同时允许使用圆括号来强制改变运算顺序。

控制成分

控制成分规定了语言允许表述的控制结构(Control Structures)。程序员利用这些结构来设计和实现程序中语句的执行顺序,即构建程序的控制逻辑。理论上已证明,任何可计算问题的程序都可以仅使用**顺序(Sequence)、选择(Selection)和循环(Iteration/Loop)**这三种基本控制结构来描述(结构化程序设计定理)。

以下是这三种基本控制结构的描述:

顺序结构(Sequential Structure): 这是最简单也是默认的控制结构,表示一系列计算操作按照它们在程序代码中出现的顺序依次执行。从第一个操作开始,直到序列的最后一个操作完成。如下图所示的流程,操作 A 执行完毕后紧接着执行操作 B。顺序结构内部可以包含其他控制结构。

选择结构(Selection Structure / Branching Structure): 选择结构提供了根据某个条件的是否满足来决定执行哪段代码路径的逻辑。最基本的形式是基于条件 P 的真假,决定是执行代码块 A 还是代码块 B(双分支),如下图 (a) 所示。程序设计语言也常提供简化形式,即只有在条件 P 成立时才执行代码块 A,否则跳过(单分支),如下图 (b) 所示。选择结构中的代码块 A 或 B 自身也可以是任意复杂的控制结构(包括顺序、选择和循环)。

循环结构(Loop Structure / Iteration Structure): 循环结构用于描述重复执行某段代码(循环体)的过程。循环通常包含以下关键部分:初始化(设置循环变量或状态)、循环条件(判断是否继续循环)、循环体(需要重复执行的代码)和更新(修改循环变量或状态以趋向于循环终止)。循环结构主要有两种基本形式:

While 型循环(入口条件循环): 先判断循环条件 P,若条件为真,则执行循环体 A,然后再次判断条件;若条件为假,则终止循环。这种结构保证了循环体可能一次也不执行。如下图 (a) 所示。Do-While 型循环(出口条件循环): 先执行循环体 A,然后判断循环条件 P,若条件为真,则继续执行循环体 A 并再次判断条件;若条件为假,则终止循环。这种结构保证了循环体至少会被执行一次。如下图 (b) 所示。

C/C++ 语言提供了丰富具体的语法结构来实现上述基本控制结构:

复合语句(Compound Statement): 使用花括号 {} 将一系列声明和语句组合成一个单一的语句单元,常用于需要将多条语句作为整体出现的地方(如循环体、分支体)。选择语句:

if 语句:实现双分支或单分支选择 (if (...) statement; else statement; 或 if (...) statement;)。当有多个 else if 时,构成多级分支。需要注意 else 与最近未配对的 if 匹配规则。switch 语句:实现基于整型或字符型表达式值的多分支选择。通过 case 标签匹配值,执行对应的代码块。break 语句用于跳出 switch 结构,若省略则会出现“穿透”(fall-through)现象,继续执行下一个 case 或 default 的代码。default 子句处理所有未匹配的情况。 循环语句:

while 语句:典型的入口条件循环 (while (condition) statement;)。先判断 condition,后执行 statement。do-while 语句:典型的出口条件循环 (do { statement; } while (condition);)。先执行 statement,后判断 condition。for 语句:提供一种紧凑的循环结构,常用于已知循环次数或涉及循环变量按规律变化的场景 (for (initialization; condition; update) statement;)。它等价于 initialization; while (condition) { statement; update; }。for 语句的三个表达式都可以省略。

此外,C/C++ 还提供了 goto 语句(不推荐使用,因其容易破坏程序结构)、break 语句(用于跳出最内层循环或 switch)和 continue 语句(用于跳过当前循环迭代的剩余部分,进入下一轮循环判断)。

4.3 传输成分与函数

程序设计语言的传输成分规定了数据在程序中移动或复制的方式。这主要包括:

赋值操作(Assignment): 将一个表达式的值赋给一个变量,改变变量的状态。数据输入/输出(Input/Output, I/O): 程序与外部环境(如用户、文件、网络)交换数据的方式,包括从外部获取数据(输入)和向外部发送数据(输出)。

在许多程序设计语言,尤其是过程式和面向对象语言中,函数(或称过程、方法) 是组织代码和实现模块化的核心机制。一个程序通常由一个或多个函数组成,每个函数负责完成一个特定的任务。在 C/C++ 程序中,main 函数是程序执行的入口点。

函数的使用涉及以下三个主要概念:

函数定义(Function Definition): 提供了函数的完整实现,包括函数首部(Function Header)和函数体(Function Body)。函数首部指定了函数的返回类型、函数名称以及形式参数列表(及其类型),说明了函数接收什么输入以及产生什么类型的输出。函数体包含实现函数功能的具体语句序列。 函数定义的一般形式(C/C++):

返回类型 函数名 (形式参数列表) // 函数首部

{

// 函数体:实现功能的语句

}

在 C/C++ 中,函数定义不允许嵌套,即不能在一个函数的内部定义另一个函数。

函数声明(Function Declaration)/ 函数原型(Function Prototype): 在调用一个函数之前,通常需要先对其进行声明(特别是在调用点出现在定义点之前的情况下)。函数声明向编译器提供了函数的签名信息,包括函数的名称、返回类型以及参数的类型和数量。其主要目的是让编译器在函数调用点能够进行类型检查,确保传递的参数与函数期望的参数类型和数量一致,并了解函数的返回值类型。 函数声明的一般形式(C/C++):

返回类型 函数名 (参数类型列表); // 参数名可选,但类型必须列出

函数调用(Function Call): 在程序的某个地方通过函数名称来执行已定义的函数。当一个函数(调用函数)需要使用另一个函数(被调用函数)的功能时,就发生函数调用。调用函数时,需要提供与被调用函数形式参数对应的实际参数(实参)。执行函数调用时,程序的控制权从调用函数转移到被调用函数,被调用函数执行完毕后,控制权通常返回给调用点(除非发生异常或提前退出)。 函数调用的一般形式(C/C++):

函数名 (实际参数列表);

理解函数调用只需知道其功能、如何提供输入(实参)以及可能返回什么结果,通常无需关心其内部实现细节(抽象)。函数可以调用自身,这称为递归调用(Recursive Call)。

函数调用时,调用函数与被调用函数之间通过参数进行信息交换。主要的参数传递方式有两种:

值传递(Call by Value): 调用时将实际参数的值复制一份传递给对应的形式参数。在函数内部对形式参数的任何修改都只影响形式参数的副本,不会影响到函数外部的实际参数。C 语言默认采用值传递。为了在 C 语言中实现函数内部对外部变量的修改,通常需要传递变量的地址(即使用指针),函数通过指针间接访问和修改原始变量。虽然传递的是地址,但地址本身是按值传递的。

引用传递(Call by Reference): 调用时将实际参数的引用(或别名)传递给对应的形式参数。形式参数不再是实参的副本,而是实参本身的一个别名。在函数内部对形式参数的任何修改都会直接作用于函数外部的实际参数。C++ 引入了引用类型 (&) 来直接支持引用传递,如下面的 swap 函数示例:

void swap(int& x, int& y) { // 形参 x 和 y 是实参的引用

int temp = x;

x = y; // 修改 x 直接修改对应的实参

y = temp; // 修改 y 直接修改对应的实参

}

// 调用示例:

// int a = 5, b = 10;

// swap(a, b); // 调用后 a 和 b 的值被交换

在 swap(a, b) 调用中,x 成为 a 的别名,y 成为 b 的别名。函数内对 x 和 y 的操作直接作用于 a 和 b。

函数作为模块化单位,极大地提高了代码的组织性、可读性、可维护性和重用性,是现代程序设计中不可或缺的基本成分。

五、总结

本文系统地概述了程序设计语言。探讨了其作为描述计算过程的人工语言的本质,追溯了从低级到高级、抽象层次不断提升的发展历程,并阐述了编译与解释两种核心执行机制,以及语法、语义、语用这三大构成要素。

回顾程序设计语言的发展概况,介绍了多款代表性语言,并依据核心思想将其划分为命令式/结构化、面向对象、函数式和逻辑式等主要编程范式。

深入解析了所有程序设计语言都具备的基本成分:数据、运算、控制和传输(特别是函数机制)。理解这些基础知识,有助于更全面地认识和学习各类程序设计语言,掌握其表达和实现计算的能力。