《程序是怎么跑起来的》第八章 从源文件到可执行文件
8.1 计算机只能运行本地代码
用某种编程语言编写的程序称为源代码,保存源代码的文件称为源文件。因为源文件是简单的文本文件,所以用Windows自带的记事本等文件编辑器就可以编写
源代码是无法直接运行的,这是因为CPU能够直接解析并运行的不是源代码而是本地代码的程序。本地这一词有母语的意思,对CPU来说,母语就是机器语言,而转换成机器语言的程序就是本地代码。用任何编程语言编写的源代码,最后都要翻译成本地代码,否则CPU不能理解
8.2 本地代码的内容
Windows种EXE文件的程序内容,使用的就是本地代码。本地代码是人无法理解的,正因如此,才有了C等编程语言来编写源代码,再将源代码转换成本地代码这一方法
可以将EXE文件的内容DUMP一下,DUMP指把文件的内容,每个字节用2位16进制数来表示的方式,本地代码的内容其实就是各种数值的罗列。每个数值都表示某一个命令或数据
计算机是把所有信息作为数值的集合来处理的,计算机指令也是数值的罗列,这就是本地代码
8.3 编译器负责转换源代码
能够把C语言等高级编程语言编写的源代码转换成本地代码的程序称为编译器,每个编写源代码的程序语言都需要其专用的编译器
编译器首先读入代码的内容,然后将其转换成本地代码。编译器中好像有一个源代码同本地代码的对应表,但实际上,仅靠对应表无法生成本地代码,读入的源代码还要经过语法解析,句法解析,语义解析等,才能生成源代码
根据CPU类型的不同,本地代码的类型也不同,所以编译器不仅和编程语言的种类有关,和CPU的类型也是相关的,编译器本身也是程序的一种,所以也需要运行环境
8.4 仅靠编译无法得到可执行文件
编译器转换源代码后,就会生成本地文件,不过本地文件无法直接运行,为了得到可以运行的EXE文件,编译后还需要进行链接处理
链接:把多个目标文件结合,生成1个EXE文件的处理就是链接,运行链接的程序叫连接器
8.5 启动及库文件
库文件指的是将多个目标文件集成保存到一个文件中的形式,连接器指定文件后,就会从中把需要的目标文件抽出来,并同其它目标文件结合生成EXE文件
printf()等函数,不是通过源代码形式而是通过库文件形式和编译器一起提供的,这样的函数称为标准函数,之所以使用库文件,是为了简化连接器的参数指定多个目标文件这一过程
8.6 DLL文件及导入库
Windows以函数的形式为应用提供了各种功能,这些形式的函数称为API 应用程序接口
在Windows中,API的目标文件,并不是存储在通常的库文件中,而是存储在名为DLL文件的特殊库文件中,DLL文件是程序运行时动态结合的文件。与之相反,存储着目标文件的实体,并直接和EXE文件结合的库文件形式称为静态链接库
8.7 可执行文件运行时的必要条件
EXE文件作为单独的文件存储在硬盘中,双击打开EXE文件,就会把EXE文件的内容加载到内存中运行
EXE文件中给变量和及函数分配了虚拟的内存地址,在程序运行时,虚拟的内存地址会转换成实际的内存地址,链接器在EXE文件的开头,追加转换内存地址所需的必要信息叫再配置信息
链接后EXE文件的构造:
8.8 程序加载会生成栈和堆
栈和堆需要的内存是在EXE文件加载到内存后开始运行时得到分配的
栈是用来存储函数内部临时使用的变量(局部变量)及函数调用时所使用的参数的内存区域
使用栈的数据的内存空间,每当函数被调用时都会得到分配申请,并在函数处理完毕后自动释放
堆是用来存储程序运行时任意数据及对象的内存领域
堆的内存空间,需要根据程序员编写的程序,来明确进行申请分配或释放
如果没有在程序中明确释放堆的空间,那么处理完程序后,这个内存空间也会一直残留,称为内存泄露,如果内存泄漏一直存在,会导致内存不足而宕机