8.从源文件到可执行文件 benben Posted on Feb 20 2023 《程序是怎样跑起来的》 ##8.1 计算机只能运行本地代码 用某种编程语言编写的程序就称为**源代码**,保存源代码的文件称为**源文件**。因为源文件是简单的文本文件,所以用Windows自带的记事本等文本编辑器就可以编写。 本地(native)这个术语有"母语的"意思。对CPU来说,母语就是机器语言,而转换成机器语言的程序就是本地代码。用任何编程语言编写的源代码,最后都要翻译成本地代码,否则CPU就不能理解。也就是说,即使是不同编程语言编写的代码,转换成本地代码后,也都变成用同一种语言(机器语言)来表示了。  ##8.2 本地代码的内容 本地代码的内容是人类无法理解的。也正是因为如此,才有了人类容易理解的C语言等编程语言来编写源代码,然后再将源代码转换成本地代码这一方法。 用记事本打开EXE文件后出现了无法理解的文字  接下来我们把刚才的EXE文件的内容Dump一下。Dump是指把文件的内容,每个字节用2位十六进制数来表示的方式。本地代码的内容就是各种数值的罗列,这一点想必大家都了解。而这些数值都表示某一个命令或数据。这里我们用的是原始的Dump程序。  计算机就是把所有的信息作为数值来处理的。与此同时,计算机的指令也是数值的罗列。这就是本地代码。 ##8.3 编译器负责转换源代码 能够把C语言等高级编程语言编写的源代码转换成本地代码的程序称为**编译器**。每个编写源代码的编程语言都需要其专用的编译器。 编译器首选需要读入代码的内容,然后再把代码转换成本地代码。编译器就好像有一个源代码同本地代码的对应表。但实际上,仅仅靠对应表是无法生成本地代码的。读入的源代码还要经过语言解析、句法解析、语义解析等才能生成本地代码。 根据CPU类型的不同,本地代码的类型也不同。因而,编译器不仅和编程语言的种类的种类有关,和CPU的类型也是相关的。  ##8.4 仅靠编译是无法得到可执行文件的 编译器转换源代码后,就会生成本地文件。不过,本地文件是无法直接运行的。为了得到可以运行的EXE文件,编译之后还需要进行"链接"处理。 编译后生成的不是EXE文件,而是拓展名为".obj"的**目标文件**,虽然目标文件的内容是本地代码,但却无法直接运行,这是因为当前程序还处于未完成状态。 把多个目标文件结合,生成1个EXE文件的处理就是**链接**,运行连接的程序就称为**链接器**(linkage editor或连接器)。 ##8.5 启动及库文件 *.obj这个文件记述的是同所有程序起始位置相结合的处理内容,称为程序的**启动**。因而,即使程序不调用其他目标文件的函数,也必须要进行链接,并和启动结合起来。 **库文件**指的是把多个目标文件集成保存到一个文件中的形式。链接器指定库文件后,就会把需要的目标文件抽取出来,并同其他目标文件结合生成EXE文件。 例:链接器的错误信息  **外部符号**是指其他目标文件中的变量或函数。 代码中记述的函数名同目标文件中的函数名有一些差异,不过大家只需要把它理解成这是C语言的规定即可。 通过以目标文件的形式或集合多个目标文件的库文件形式来提供函数,就可以不用公开标准函数的源代码内容。 ##8.6 DLL文件及导入库 Windows以函数的形式提供了各种功能。这些形式的函数称为**API**(Application Programming Interface,应用程序接口)。 Windows中,API的目标文件,并不是存储在通常的库文件中,而是存储在名为**DLL文件(Dynamic Link Library)**的特殊库文件中。DLL文件是程序运行时动态结合的文件。 目标文件的实体并不存在的库文件称为**导入库**。 与此相反,存储着目标文件的实体,并直接和EXE文件结合的库文件称为**静态链接库**。  ##8.7 可执行文件运行时必要条件 EXE文件中给变量以及函数分配了虚拟的内存地址。在程序运行时,虚拟的内存地址会转换成实际的内存地址。链接器会在EXE文件中的开头,追加转换内存 ##8.8 程序加载时会生成堆和栈 ##8.9 有点难度的Q&A 赠人玫瑰,手留余香 赏 Wechat Pay Alipay 单例设计模式 7.程序是在何种环境中运行的