C++编译连接全过程
2016-09-06 14:35
239 查看
C++编译连接全过程:
1)编译预处理。
2)编译,优化阶段。
3)汇编过程。
4)连接程序。
<2>条件编译:
<3>文件包含:
<4>布局控制:
<5>其他:
(1)词法分析。
(2)语法分析。
(3)语义分析。
(4)中间代码生成。
(5)代码优化。
(6)代码生成。
以上阶段我们将跳过<1>到<5>这几个步骤,直接跳到代码生成的步骤。
<2>生成单元包含的最少元素:
每个经过预处理的源文件经过编译最终都会生成一个目标文件,该目标文件最少包含如下三个表:
(1),未解决符号表:列出了本单元里有引用但是不在本单元定义的符号及其出现的地址。
(2),导出符号表:提供了本编译单元具有定义,并且可以提供给其他编译单元使用的符号及其在本单元中的地址。
以上两点的具体例子:
(3)地址重定向表:提供了本编译单元所有对自身地址的引用记录。
<3>C++中特例:
(1)extern:
这是告诉编译器,这个符号在别的编译单元里定义,也就是要把这个符号放到未解决符号表里去。(外部链接)。
(2)Static:
如果该关键字位于全局函数或者变量的声明的前面,表明该编译单元不导出这个函数/变量的符号。因此无法在别的编译单元里使用。(内部链接)。如果是static局部变量,则该变量的存储方式和全局变量一样,但是仍然不导出符号。
(3)const:
默认内部链接,(可以通过添加extern和static改变链接属性)。
(1)代码段:该端中所包含的主要是程序的指令,该段一般是可读和可执行的,一般不可写。
(2)数据段:主要存放程序中要用到的各种全局变量或静态的数据,一般数据段都是可读,可写,可执行。
当连接器进行连接的时候,首先决定各个目标文件在最终可执行文件里的位置。然后访问所有目标文件的地址重定义表,对其中记录的地址进行重定向(加上一个偏移量,即该编译单元在可执行文件上的起始地址)。然后遍历所有目标文件的未解决符号表,并且在所有的导出符号表里查找匹配的符号,并在未解决符号表中所记录的位置上填写实现地址。最后把所有的目标文件的内容写在各自的位置上,再作一些另外的工作,就生成一个可执行文件了。
<2>静态链接
此钟链接方式下,函数的代码将从器所在的静态链接库中被拷贝到最终执行程序中,这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中,静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
<3>动态链接
此种方式下,函数的代码会被放在动态链接库或共享对象的某个目标文件中,链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其他少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一些内存,但某些情况下动态链接可能带来一些性能上的损害。
参考文献
C++之编译器与链接器工作原理
http://www.cnblogs.com/kunhu/p/3629636.html
C&C++编译过程详解
http://www.360doc.com/content/14/0109/16/835125_343879650.shtml
声明:
该文仅作学习与记录之用,欢迎技术纠错和讨论;
非技术性言论皆为一家之谈,如有不同意见请坚持己见;
如有雷同可能为学习汝之所得,请各位巨人的肩膀还请继续空出位置。
1)编译预处理。
2)编译,优化阶段。
3)汇编过程。
4)连接程序。
一,编译预处理:
<1> 宏替换://将程序中所有Name替换为StringToken(字符串中的Name除外) #define Name StringToken //取消程序中接下来Name的宏定义 #undef Name
<2>条件编译:
//根据宏的条件进行屏蔽对应的代码段 #ifdef Name1 code1 #elif Name2 code2 #endif
<3>文件包含:
//文件包含原理,简单来说就是将头文件的代码与当前源文件进行连接成新的源文件,也就是普通的复制粘贴。 #include "A.h"
<4>布局控制:
//为编译程序提供非常规的控制流信息 #progma once
<5>其他:
//"\","##","#","#@"各种宏连接符号 #define user_max(a,b) \ ((a) > (b) ? (a) : (b)); //一些系统宏的替换 cout<<"__LINE__:"<<__LINE__<<endl; asset(); ......
二,编译,优化阶段。
<1>具体过程:(1)词法分析。
(2)语法分析。
(3)语义分析。
(4)中间代码生成。
(5)代码优化。
(6)代码生成。
以上阶段我们将跳过<1>到<5>这几个步骤,直接跳到代码生成的步骤。
<2>生成单元包含的最少元素:
每个经过预处理的源文件经过编译最终都会生成一个目标文件,该目标文件最少包含如下三个表:
(1),未解决符号表:列出了本单元里有引用但是不在本单元定义的符号及其出现的地址。
(2),导出符号表:提供了本编译单元具有定义,并且可以提供给其他编译单元使用的符号及其在本单元中的地址。
以上两点的具体例子:
extern int n; //此为声明,需要查找外部定义,该变量将会作为地址添加进没解决符号表 int m = 1; //此为定义,该变量将会添加导出符号表 void fun() //该函数将会添加进导出符号表 { ++n; }
(3)地址重定向表:提供了本编译单元所有对自身地址的引用记录。
<3>C++中特例:
(1)extern:
这是告诉编译器,这个符号在别的编译单元里定义,也就是要把这个符号放到未解决符号表里去。(外部链接)。
(2)Static:
如果该关键字位于全局函数或者变量的声明的前面,表明该编译单元不导出这个函数/变量的符号。因此无法在别的编译单元里使用。(内部链接)。如果是static局部变量,则该变量的存储方式和全局变量一样,但是仍然不导出符号。
(3)const:
默认内部链接,(可以通过添加extern和static改变链接属性)。
三,汇编阶段。
汇编过程实际上指吧汇编语言代码翻译成目标机器指令,对于每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件存放的就是与源程序等效的机器语言代码。目标文件通常由段组成,至少包含两个端:(1)代码段:该端中所包含的主要是程序的指令,该段一般是可读和可执行的,一般不可写。
(2)数据段:主要存放程序中要用到的各种全局变量或静态的数据,一般数据段都是可读,可写,可执行。
四,连接程序
<1>基本顺序当连接器进行连接的时候,首先决定各个目标文件在最终可执行文件里的位置。然后访问所有目标文件的地址重定义表,对其中记录的地址进行重定向(加上一个偏移量,即该编译单元在可执行文件上的起始地址)。然后遍历所有目标文件的未解决符号表,并且在所有的导出符号表里查找匹配的符号,并在未解决符号表中所记录的位置上填写实现地址。最后把所有的目标文件的内容写在各自的位置上,再作一些另外的工作,就生成一个可执行文件了。
<2>静态链接
此钟链接方式下,函数的代码将从器所在的静态链接库中被拷贝到最终执行程序中,这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中,静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
<3>动态链接
此种方式下,函数的代码会被放在动态链接库或共享对象的某个目标文件中,链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其他少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一些内存,但某些情况下动态链接可能带来一些性能上的损害。
参考文献
C++之编译器与链接器工作原理
http://www.cnblogs.com/kunhu/p/3629636.html
C&C++编译过程详解
http://www.360doc.com/content/14/0109/16/835125_343879650.shtml
声明:
该文仅作学习与记录之用,欢迎技术纠错和讨论;
非技术性言论皆为一家之谈,如有不同意见请坚持己见;
如有雷同可能为学习汝之所得,请各位巨人的肩膀还请继续空出位置。
相关文章推荐
- c语言二叉树和二叉搜索树的实现
- C++类型萃取
- 深入C++对象模型&虚函数表
- 2016年8月问题记录与总结
- C/C++预编译指令总结
- C++学习笔记(六)-- 类和对象 构造函数和析构函数 const成员函数 this指针 对象数组 堆栈管理变量
- C++实现二维字符串数组
- C++ Primer Plus (Six Edition) Chapter 2, Programming Exercises
- 有向强连通图的Tarjan算法
- C++ 类的派生和继承
- 绘制2D学习一
- 1003. Emergency (25)
- C++ 大整数宝宝加加乐(九度OJ 1198)
- C++如何只在堆上或者栈上生成对象
- C++智能指针类模板
- C++:类的自动转换和强制类型转换
- C++STL中String类的分析与运用
- C++按照数字增长生成图像文件路径
- C++ 类的使用
- 什么是交叉编译,为什么要使用交叉编译?