- 内容提要
- 序 1:程序里的世界
- 序 2:最后一层表象
- 关于本书
- 致谢
- 引言:简单的本源
- 篇一:计算系统
- 第 1 章 数,以及对数据的性质的思考
- 第 2 章 逻辑
- 第 3 章 抽象
- 篇二:语言及其面临的系统
- 第 4 章 语言
- 第 5 章 从功能到系统
- 篇三:程序设计的核心思想
- 第 6 章 数据结构:顺序存储
- 第 7 章 数据结构:散列存储
- 第 8 章 执行体与它在执行过程中的环境
- 第 9 章 语法树及其执行过程
- 第 10 章 对象系统:表达、使用与模式
- 篇四:应用开发基础
- 第 11 章 应用开发的背景与成因
- 第 12 章 应用开发技术
- 第 13 章 开发视角下的工程问题
- 第 14 章 应用程序设计语言的复杂性
- 篇五:系统的基础部件
- 第 15 章 分布
- 第 16 章 依赖
- 第 17 章 消息
- 第 18 章 系统
- 篇六:系统的基本组织方法与原理
- 第 19 章 行为的组织及其抽象
- 第 20 章 领域间的组织
- 附一:主要编程范式 及其语言特性关系
- 附二:继承与混合,略谈系统的构建方式
- 附三:像大师们一样思考——从 UML 何时死掉 谈起
- 附四:VCL 已死,RAD 已死
8.7 所谓操作系统,不过是参考环境更复杂的执行体而已
我们已经讨论四点:
- 关联数组的实质是“名/值”映射;
- 代码中的数据与逻辑可以统一为数据,进而统一为标识;
- 关联数组可以维护一个计算过程所需的参考,亦即上下文环境;
- 对于静态语言来说,上下文环境的实质是一个不需要名字/标识的(或称标识可选的)关联数组——这种情况下,它更像一个索引数组。
综上所述,对于静态的、编译型语言来说,下面的代码:
1 2 3 4 5 6 7 8 |
|
意味着 P()
这个计算过程所需的环境有两个,其一是 x1
, x2 … xn
,它们在 P()
进行计算之前就可以预知;其二是 y1...yn
,它们在 P()
计算的当时才会得知。对于编译型语言来说,它认为:
- X 是 P() 计算的前设;且,
- X 与 P 本身是后续其他计算的前设;继续推论之,则,
- 所有在最外层出现的标识是整个系统运算的前设。
由此,编译型语言通过编译器程序
- 将所有这些标识与其内容——例如数据、函数(逻辑、行为),
- 根据所有计算过程约定的计算环境——例如操作系统,
- 按照确认的规则——例如可执行文件格式,
编排并放在一个实体文件中。最后,操作系统(桌面用户或服务进程)决定何时将该实体文件装载并运行(Launch)起来,以完成所需的全部计算。
我们看到上述过程的限制条件包括:操作系统环境、可执行文件格式和编排方法。这些是程序得以执行的要件,但并非我们需要讨论的内容主体。因此,图 14 以 32 位 Windows 为例,仅大体说明这些要件之间的关系:
图 14 从一个入口开始:操作系统准备的执行环境
参考图 14,对于操作系统来说,仅需要知道一个程序的 “入口代码位置” 。例如:
1 2 3 4 |
|
随后,入口代码将按照规则在 “代码表” 中查找标识,例如:
1 2 3 4 5 6 7 |
|
最后,如果 P
或 main
需要数据,则使用类似的方法通过 “数据表” 来查找标识。
编译型语言在程序执行前就明确这些标识,因此编译过程可以省去这些名字,而指代以存储中的索引,亦即地址;因为上述规则是操作系统对存储的约定,所以对于编译型语言来说,该可执行文件(PE 文件,Portable Execute)可以置入存储环境中,以应用上述地址;因为操作系统知道上述 PE 文件的入口地址,所以只需要:
- 装载该 PE 文件、
- 分配地址、
- 交出 CPU 的执行权限,
然后就可以完成整个计算过程。
如上图所见,节表是节的索引,是节中的数据与代码 5 (及其标识),是整个计算过程的参考——上下文环境。推而广之,对于整个进程来说,它可以通过导入表来获得整个操作系统的上下文环境;细究之,对于一个内部函数来说,它可以通过入口参数表来得到上下文环境(例如此前讨论的 y1...yn
),进一步也可以得到进程的、操作系统的上下文环境。
总结这所有的行为,仅仅只有两种 6 :1、找到(包括逻辑在内的)数据;2、计算。
那么对于解释型语言来说,上述过程是更复杂,亦或更简单呢?
- 这里用“船”而不是“独木舟”(canoe/boat)的原因,仅出于中文在行文上的方便。 ↩
- 这也意味着有些知识是不能复制的。 ↩
- 我们将
ship
理解为行为的定义,而将ship()
理解为行为的能力——这出于程序与抽象表达上的需要,而与英文的惯例是不同的。一旦使用ship()
,则说明是指该“划船”作为一个系统的、整体的行为的实施过程。 ↩ - 我们还没有讨论到动态/静态语言这一分类方法。这里简单地从标识角度来定义它们,即静态语言是指标识(例如“变量”)在程序执行前就已经完全预知的,动态语言则允许在程序执行过程中新建它们。 ↩
- 这里是特指可以执行的机器指令。 ↩
- 这里的推论是相当重要的。综合上述的讨论,我们对于一个环境的依赖,事实上可以看成对“定义与查找(数据)”这样的行为的依赖。再进一步,这也就揭示了我们的计算环境之于“数与算”的抽象本质,以及将数据结构(包括以此为基础的种种算法)作为核心研究领域的真实原因。 ↩
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论