C/C++编译过程详解(转载)

C/C++编译过程  
  
C/C++编译过程主要分为4个过程  
1) 编译预处理  
2) 编译、优化阶段  
3) 汇编过程  
4) 链接程序  
  
一、编译预处理  
  
(1)宏定义指令,如#define Name TokenString,#undef等。 对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,  
  
但作为字符串常量的 Name则不被替换。对于后者,则将取消对某个宏的定义,使以后该串的出现不再被替换。  
  
(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。 这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。  
  
预编译程序将根据有关的文件,将那些不必要的代码过滤掉  
  
(3) 头文件包含指令,如#include "FileName"或者#include 等。 在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),  
  
同时包含有各种外部符号的声明。 包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。  
  
在程序中#include它们要使用尖括号(< >)。  
  
另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。  
  
(4)特殊符号,预编译程序可以识别一些特殊的符号。 例如在源程序中出现的#line标识将被解释为当前行号(十进制数),  
上面程序实现了对宏line的运用  
  
(5)预处理模块 预处理工作由#pragma命令完成,#Pragma命令将设定编译器的状态或者是指示编译器完成一些特定的动作。  
  
#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。  
  
依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。  
打开C标准库函数,如stdio.h,我们总能找到下面这一句指示编译器初始化堆栈  
#include "iostream"  
#line 100  
using namespace std;  
int main(int argc, char* argv[])  
{  
cout<<"__LINE__:"<<__LINE__<  
int main(int argc, char* argv[])  
{  
printf("hello world");  
return 0;  
}  
_Check_return_opt_ _CRTIMP int __cdecl printf(_In_z_ _Printf_format_string_ const char * _Format, ...);  
#define CALLBACK _stdcall /* Windows程序回调函数*/  
#define WINAPI _stdcall  
#define WINAPIV _cdecl  
#define PASCAL _stdcall /*在c++语言中使用了StandardCall调用方式*/  
#define PASCAL _cdecl/*在c语言中使用了C DECLaration调用方式*/  
C/C++编译过程  
b) 循环  
c) 循环的查找  
d) 可归约流图  
e) 循环优化  
3) 数据流的分析与全局优化  
a) 一些主要的概念  
b) 数据流方程的一般形式  
c) 到达一定值数据流方程  
d) 可用表达式及其数据流方程  
e) 活跃变量数据流方程  
f) 复写传播  
经过优化得到的汇编代码必须经过汇编程序的汇编转换成相应的机器指令,方可能被机器执行。  
  
三、汇编过程   
  
汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,  
  
都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。  
  
目标文件由段组成。通常一个目标文件中至少有两个段: 代码段:该段中所包含的主要是程序的指令。  
  
该段一般是可读和可执行的,但一般却不可写。 数据段:主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。  
  
四、链接程序  
  
由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。  
  
例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);  
  
在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。  
  
链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,  
  
使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。  
  
根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:  
  
(1)静态链接 在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。  
  
这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,  
  
其中的每个文件含有库中的一个或者一组相关函数的代码。   
  
(2) 动态链接  
在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。  
链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量  
的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应  
进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。  
C/C++编译过程  
对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动  
态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一  
些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一  
  
定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。  
  
-----------------------------------------------------------------------------------------------------------------------------------作者  张彦升

你可能感兴趣的:(C/C++)