《程序是怎么跑起来的》读书笔记(8) -- 从源文件到可执行文件

源代码完成后,就可以编译执行可执行文件了,负责实现的是编译器
用某种编程语言编写的程序就称为源代码,保存源代码的文件被称为源文件。
源文件就是简单的文本文件,所以一般记事本就可以做编辑器。

但是源代码是无法直接运行的,因为cpu能直接运行的并不是源代码,而是本地代码的程序

本地这个单词是native,有母语的意思,对cpu来说,母语就是本地代码,用任何编程语言编写的源代码,最后都会被翻译成本地代码,任何语言最后都会变成同一种语言,机器语言

java的native关键字

EXE文件

windows的exe文件就是典型的本地文件,使用的本地代码。
用记事本打开exe文件是无法理解的,因为本地代码一般用两位16进制的数字表示,而文本是8个字节
DUMP:一般是指把文件的内容的每个字节直接用2位16进制数来表示。
将EXE文件dump后,会发现是各种数值的罗列,而这些数值就是本地代码的真面目。每个数值都代表某一个命令或者数据。
而计算机就是把所有的信息都当作数值去处理 例如A就是16进制数的41来控制

编译器负责转换源代码

能够把高级程序语言编写的源代码转化成本地代码的程序称为编译器。
每个编写源代码的编程语言都需要其专用的编译器。
c语言就是c编译器
编译器转化源代码过程

仅靠编译无法得到可执行文件

本地文件是无法直接运行的,为了得到可以运行的exe文件,编译之后还需要进行“连接”处理
例如对.c文件编译后,并没有直接生成exe文件,而是扩展名为.obj的目标文件。
虽然目标文件已经是本地代码,但是无法对其直接运行,因为当前程序还处于未完成状态。因为源代码中会包括一些源代码中未定义或者调用的函数。这些函数必须和生成的obj文件结合才可以
利用连结器命令将一些lib文件与生成的obj文件,就会生成exe文件

启动和库文件

库文件是把多个目标文件集成保存到同一个文件当中,当连结器指定库文件后,就会把需要的目标文件抽取出来,并同其他目标文件结合生成EXE文件
例如sprintf()函数,不是通过源代码形式而是通过库文件形式和编译器一起提供的,这样的函数被叫做标准函数。之所以使用库文件,是为了简化为连接器的参数指定多个目标文件这一过程,因为如果要引用几百个目标文件,太繁琐了,所以库文件很方便
另外一个好处是,不开源这些编译,这些对于一些公司来说是很重要的财产。

DLL文件以及导入库

Windows以函数的形式为应用提供了很多功能,统称为API(Application, programming interface),应用程序接口。例如c语言的MessageBox(),这些并不是c语言的标准函数,而是Windows的api

api文件并不是存储在通常的库文件中,而是存储在DLL文件(Dynamic Link Library 动态链接库),DLL文件是程序运行时动态结合的文件。 import32.lib仅仅存储两个信息,一个是MassageBox()在user32.dll文件里,另一个这存储这dll文件的文件夹信息。实际上MessageBox的目标文件的实体实际上并不存在。所以import32.lib就是导入库

另外,存储这对应目标文件的实体,并直接与EXE文件结合的库文件形式称为静态连接库。cw32lib就是静态连接库

EXE文件的运行

EXE文件的内容被分为再配置信息,变量组和函数组
当程序加载到内存中时,还会生成两个组,栈和堆
栈是用来存储函数内部的临时用的变量以及函数调用时所用的参数内存区域。
堆是用来存储程序运行时的任意数据及对象的内存领域。
两者的相似之处是都是在程序运行时得到申请分配的。但是栈对数据进行存储和舍弃是编译器自动生成的,不需要程序猿的参与,函数处理完毕自动释放。但堆的内存空间,是根据程序猿编写的程序,进行申请分配和释放。
内存泄漏就是因为堆内存空间一直没有被释放堆满了。

发表评论

电子邮件地址不会被公开。