C++的编译过程
- C++的编译过程(摘自:http://www.cnblogs.com/dongdongweiwu/p/4743709.html)
- 了解编译过程的益处
- c++工程相关的问题
- 什么是库?静态库和动态库又有什么区别?
- 头文件起什么作用?
- c++工程相关的问题
- 编译过程简介
- 名词:
- 编译:把源文件中的源代码翻译成机器语言,保存到目标文件中。如果编译通过,就会把CPP转换成OBJ文件。
- 编译单元:
- 每个cpp就是一个编译单元,每个编译单元相互之间是独立且相互不知的。一个编译单元(Translation Unit)是指一个.cpp文件以及这所include的所有.h文件,.h文件里面的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,后者拥有PE(Portable Executable,即Windows可执行文件)文件格式,并且本身包含的就是二进制代码,但是不一定能执行,因为并不能保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方式编译完毕后,再由链接器进行链接成为一个.exe或.dll文件。
- 目标文件:编译后生成的文件,以机器码的形式包含了编译单元里所有的函数和数据、导出符号表、未解决符号表、地址重定向表等
- 目标文件的类型:
- 可重定位文件(.o、.obj文件):其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据。每个cpp会被编译成一个.o文件
- 共享的目标文件(库文件)
- 这种文件存放了适合于在两种上下文里链接的代码和数据。
- 第一种是链接程序(静态库)可把它与其它可重定位文件及共享的目标文件一起处理来创建另一个目标文件
- 静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码
-
第二种是动态链接程序(动态库)将它与另一个可执行文件及其它的共享目标文件结合到一起,创建一个进程映象
- 动态链接库在程序执行时才被调用
- 第一种是链接程序(静态库)可把它与其它可重定位文件及共享的目标文件一起处理来创建另一个目标文件
- 这种文件存放了适合于在两种上下文里链接的代码和数据。
- 可执行文件
- 一个可以被操作系统创建一个进程来执行之的文件
- .o文件在编译后就能获得,但是库文件、可执行文件都需要在链接后才能获得
- 目标文件的类型:
- c++程序编译过程图
-
- 编译过程
- 作用:编译是读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再转换为机器代码,生成目标文件(.obj)
- 分为两个过程
- 编译:
- 预处理阶段
- 宏#define
- 条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。
- 头文件包含,#include <iostream>
- 特殊符号
-
LINE标识将被解释为当前行号(十进制数)
-
FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换
-
- 编译、优化阶段
- 针对代码优化,不依赖具体计算机
- 针对计算机优化
- 预处理阶段
- 汇编
- 把汇编语言代码翻译成目标机器指令,生成目标文件(.o文件、.obj文件)。此过程会依赖机器的硬件和操作系统环境。
- 编译:
- 3张表:.o文件至少要提供3张表
- 导出符号表:即该目标文件可以提供的符号及地址
- 未解决符号表:即找不到地址的符号的列表,告诉链接器这些符号没找到地址
- 地址重定向表:
- 链接的时候,链接器会为目标文件的“未解决符号表”里的符号在其他目标文件中寻找地址,但是每个目标文件的地址都是从0x0000开始的,这样直接将对方文件中符号的地址拿过来用显然会是不正确的,为了区分不同的文件,链接器在链接时就会对每个目标文件的地址进行调整。在这个例子中,假如B.obj的0x0000被定位到可执行文件的0x00001000上,而A.obj的0x0000被定位到可执行文件的0x00002000上,那么实现上对链接器来说,A.obj的导出符号地地址都会加上0x00002000,B.obj所有的符号地址也会加上0x00001000。这样就可以保证地址不会重复。
- 因为被加上了起始地址,所以符号在自身文件中的实际地址就不对了,需要再用一张地址重定向表记录符号相对自身文件的地址
- 名词: