程序的编译过程---预处理,编译优化, 汇编, 链接

本文详细介绍了C/C++代码转化为计算机可执行语言的四个阶段:预处理(处理宏定义、条件编译、头文件包含和特殊符号),编译和优化(生成.s文件,包括局部优化、控制流分析、循环优化和全局优化),汇编(生成.o文件),以及链接(静态链接和动态链接)。通过对这些步骤的理解,读者可以更好地掌握程序编译原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

c/c++代码转换成计算机能够执行的语言要经过一下过程

 

 

 

 一、编译预处理(生成 .i 文件)

 

(1)宏定义指令

如#define Name TokenString,#undef等。 对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,但作为字符串常量的 Name则不被替换。对于后者,则将取消对某个宏的定义,使以后该串的出现不再被替换。

 

(2)条件编译

一般情况下,源程序中所有的行都参加编译。但有时希望对其中一部分内容只在满足一定条件下才进行编译,即对一部分内容指定编译条件,这就是"条件编译"。条件编译语句排版时,需考虑以下三种位置:

1)条件编译语句块与函数定义体之间不存在相互嵌套(主要在(.h)文件中);

2)条件编译语句块嵌套在函数体之外(主要在(.c)文件中);

3)条件编译语句嵌套在函数体内 (主要在(.c)文件中)。

条件编译指令将决定哪些代码被编译,而哪些是不被编译的。此步骤就是将那些不必要的代码过滤掉

 

(3)头文件包含指令

文件包含用#include指令,预处理后将指令中指明的源程序文件嵌入到当前源程序文件的指令位置处。有2种格式:

第一种方式,格式为:
    #include <文件名>
预处理器将在include子目录下搜索由文件名所指明的文件。这种方式称为“标准方式”,适用于嵌入C++提供的头文件,因为这些头文件一般都存在C++系统目录的include子目录下。

 

第二种方式,格式为:
    #include ″文件名″
预处理器将首先在当前文件所在目录下搜索,如果找不到再按标准方式搜索。这种方式适用于嵌入用户自己建立的头文件。
一个被包含的头文件中还可以有#include指令,即include指令可以嵌套。但是,如果同一个头文件在同一个源程序文件中被重复包含,就会出现标识符重复定义的错误。
例如:头文件f2.h中包含了f1.h,如果文件f3.cpp中既包含f1.h,又包含f2.h,那么编译将提示错误,原因是f1.h被包含了两次,那么其中定义的标识符在f3.cpp中就被重复定义。

(4)特殊符号处理

预编译程序可以识别一些特殊的符号。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。

总结:预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。

 

、编译、优化阶段(生成.s文件)

编译:经过预编译得到的输出文件中,将只有常量。如数字、字符串、变量的定义,以及C语言的关键字,如main,if,else,for,while,{,}, +,-,*,\,等等。预编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。

优化:优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系。优化处理主要分为下面几个过程: 

 

1) 局部优化 

a) 基本块的划分 

b) 基本块的变换  

c) 基本块的DAG表示 

d) DAG的应用 

e) 构造算法讨论 

 

2) 控制流分析和循环优化 

a) 程序流图与循环 

b) 循环 

c) 循环的查找 

d) 可归约流图 

e) 循环优化 

 

3) 数据流的分析与全局优化 

a) 一些主要的概念 

b) 数据流方程的一般形式 

c) 到达一定值数据流方程 

d) 可用表达式及其数据流方程 

e) 活跃变量数据流方程 

f) 复写传播 

经过优化得到的汇编代码必须经过汇编程序的汇编转换成相应的机器指令,方可能被机器执行

 

、汇编过程(生成 .o 文件)

  汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。 目标文件由段组成。通常一个目标文件中至少有两个段:
代码段:该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般却不可写。
数据段:主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。

 

、链接程序

 

 

 

 

由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个 源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。 链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。
根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:



(1)静态链接:

在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。

 

 

(2)动态链接:

  在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值