【编译基础知识】

注:未特殊说明,则默认为 Windows 下的 c 语言编译过程

简单Q&A

问题

1.CPU可以解析和运行的程序形式称为什么代码?

2.将多个目标文件结合生成EXE文件的工具称为什么?

3.扩展名为.obj的目标文件的内容,是源代码还是本地代码?

4.把多个目标文件收录在一起的文件称为什么?

5.仅包含Windows的DLL文件中存储的函数信息的文件称为什么?

6.在程序运行时,用来动态申请分配的数据和对象的内存区域形式称为什么?

答案

1.本地代码(机器语言代码)

2.链接器

3.本地代码

4.库文件

5.导入库

6.堆

解析

1.通过编译源代码得到本地代码。

2.通过编译和链接,得到EXE文件。

3.通过对源文件进行编译,得到目标文件。例如,C语言中,将Sample1.c这个源文件编译后,就会得到Sample1.obj这个目标文件。目标文件的内容是本地代码。

4.链接器会从库文件中抽取出必要的目标文件并将其结合到EXE文件中。此外,还存在一种程序运行时结合的DLL形式的库文件。

5.把导入库信息结合到EXE文件中,这样程序在运行时就可以利用DLL内的函数了。

6.堆的内存空间会根据程序的命令进行申请及释放。

知识点

  • 任何编程语言的源代码(源文件)必须翻译成本地代码(机器语言)后,cpu才能理解运行
  • Windows中EXE文件的程序内容,使用的就是本地代码

把刚才的EXE文件的内容Dump一下。Dump是指把文件的内容,每个字节用2位十六进制数来表示的方式。本地代码的内容就是各种数值的罗列,每个数值都表示某一个命令或数据

而计算机就是把所有的信息作为数值的集合来处理的

  • 编译器本身也是程序的一种,所以也需要运行环境(Win、Linux...),也分编程语言(C、Java...)和不同CPU的不同版本
  • 编译器转换源代码后,就会生成本地文件。不过,本地文件是无法直接运行的。为了得到可以运行的EXE文件,编译之后还需要进行“链接”处理。

编译后生成的不是EXE文件,而是扩展名为“.obj”的目标文件;虽然目标文件的内容是本地代码,但却无法直接运行,当前程序还处于未完成状态。

例如:

(1)和(2)是程序员自己作成的,处理内容记述在源代码中。

(3)和(4)源代码中都没有记述这些函数的处理内容。

因此,这时就必须将存储着sprintf()和MessageBox()的处理内容的目标文件同Sample1.obj结合,否则处理就不完整,EXE文件也就无法完成。

示例:bcc32 -W -c Sample1.c

  • 把多个目标文件结合,生成1个EXE文件的处理就是链接,运行连接的程序就称为链接器(linkage editor或连结器)。

示例:

ilink32 -Tpe -c -x -aa c0w32.obj Sample1.obj, Sample1.exe, ,

import32.lib cw32.lib

c0w32.obj这个目标文件记述的是同所有程序起始位置相结合的处理内容,称为程序的启动。(c0w32.obj是由Borland C++ Compiler提供的)

Q:“链接时不指定sprintf()和MessageBox()的目标文件也没问题么?”

A:sprintf()的目标文件在cw32.lib中,MessageBox()的目标文件在import32.lib中(实际上,MessageBox()的目标文件在user32. dll这个DLL文件中)

  • 库文件指的是把多个目标文件集成保存到一个文件中的形式。链接器指定库文件后,就会从中把需要的目标文件抽取出来,并同其他目标文件结合生成EXE文件。

像import32.lib及cw32.lib这样的文件称为库文件。

sprintf()等函数,不是通过源代码形式而是通过库文件形式和编译器一起提供的。这样的函数称为标准函数。(通过这种形式可以不公开标准函数的源代码内容)

  • Windows以函数的形式为应用提供了各种功能。这些形式的函数称为API

例如,Sample1.c中调用的MessageBox(),它并不是C语言的标准函数,而是Windows提供的API的一种。

  • Windows中,API的目标文件,并不是存储在通常的库文件中,而是存储在名为DLL(Dynamic Link Library)文件的特殊库文件中。DLL文件是程序运行时动态结合的文件。
  • MessageBox()的目标文件是存储在import32.lib中的。实际上,import32.lib中仅仅存储着两个信息,一是MessageBox()在user32.dll这个DLL文件中,另一个是存储着DLL文件的文件夹信息,MessageBox()的目标文件的实体实际上并不存在。我们把类似于import32.lib这样的库文件称为导入库。(导入库装载了函数对应的 dll 库信息)
  • 存储着目标文件的实体,并直接和EXE文件结合的库文件形式称为静态链接库。静态(static=静态的)同动态(dynamic=动态的)是相反的意思。存储着sprintf()的目标文件的cw32lib就是静态链接库

通过结合导入库文件,执行时从DLL文件中调出的MessageBox()函数这一信息就会和EXE文件进行结合

  • Windows中的编译和链接机制

  • EXE文件是作为单独的文件储存在硬盘中的。通过资源管理器找到并双击EXE文件,就会把EXE文件的内容加载到内存中运行

EXE文件中给变量及函数分配了虚拟的内存地址。在程序运行时,虚拟的内存地址会转换成实际的内存地址。链接器会在EXE文件的开头,追加转换内存地址所需的必要信息。这个信息称为再配置信息

  • 链接后的exe文件的构造

  • EXE文件的内容分为再配置信息、变量组和函数组。不过,当程序加载到内存后,除此之外还会额外生成两个组,那就是栈和堆

栈是用来存储函数内部临时使用的变量(局部变量),以及函数调用时所用的参数的内存区域。堆是用来存储程序运行时的任意数据及对象的内存领域

  • 加载到内存的程序由4部分构成

  1. EXE文件中并不存在栈及堆的组。栈和堆需要的内存空间是在EXE文件加载到内存后开始运行时得到分配的。
  2. 内存中的程序,就是由用于变量的内存空间、用于函数的内存空间、用于栈的内存空间、用于堆的内存空间这4部分构成的。(堆不释放可能会有内存泄漏问题)
  3. 栈及堆的相似之处在于,他们的内存空间都是在程序运行时得到申请分配的

进阶Q&A

Q:编译器和解释器有什么不同?

A:编译器是在运行前对所有源代码进行解释处理的。而解释器则是在运行时对源代码的内容一行一行地进行解释处理的。

Q:“分割编译”指的是什么?

A:将整个程序分为多个源代码来编写,然后分别进行编译,最后链接成一个EXE文件。这样每个源代码都相对变短,便于程序管理。

Q:“Build”指的是什么?

A:根据开发工具种类的不同,有的编译器可以通过选择“Build”菜单来生成EXE文件。这种情况下,Build指的是连续执行编译和链接

Q:使用DLL文件的好处是什么?

A:DLL文件中的函数可以被多个程序共用。因此,借助该功能可以节约内存和磁盘。此外,在对函数的内容进行修正时,还不需要重新链接(静态链接)使用这个函数的程序。

Q:不链接导入库的话就无法调用DLL文件中的函数吗?

A:通过使用LoadLibrary()及GetProcAddress()这些API,即使不链接导入库,也可以在程序运行时调用DLL文件中的函数。不过使用导入库更简单一些。

Q:“叠加链接”这个术语指的是什么?

A:将不会同时执行的函数,交替加载到同一个地址中运行。通过使用“叠加链接器”这一特殊的链接器即可实现。在计算机中配置的内存容量不多的MS-DOS时代,经常使用叠加链接。

Q:和内存管理相关的“垃圾回收机制”指的是什么呢?

A:垃圾回收机制(garbage collection)指的是对处理完毕后不再需要的堆内存空间的数据和对象进行清理,释放它们所使用的内存空间。这里把不需要的数据比喻为了垃圾。进行该处理时,C语言用的是free()函数,C++用的是delete运算符。在C++的基础上开发出来的Java及C#这些编程语言中,程序运行环境会自动进行垃圾回收。这样就可以避免由于程序员的疏忽(忘了记述内存的释放处理)而造成内存泄露了。

Java

源文件(.java)——编译器——>字节码文件(.class)——虚拟机中的解释器——>机器码——>执行

硬件——>操作系统——>Java虚拟机——>Java应用程序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值