一个cpp文件的编译过程详解

一个CPP文件的编译过程

笼统的说一个CPP文件的编译过程就是以下几步

Created with Raphaël 2.1.2 预处理(做优化,生成.i文件) 编译器(生成.s文件) 汇编器(生成.o文件) 链接器(连接库文件和其他目标代码) 生成可执行文件

c++为了兼容c程序,没有选择像java或者python之类的import当前源文件所用到的库,而是以include头文件的方式来将库的借口声明以文本替换的方式载入,然后重新解析,一个简单的helloworld程序,预处理的时候会读入将近20个头文件,预处理之后供编译器parse的源码有上万行。

g++ -E testHello.cpp -o testHello.i

c++预处理阶段主要完成的工作:处理#开始的预编译指令:
(1)宏定义(#define):对程序中所有出现的宏名,都用宏定义中的字符串去代换
(2)文件包含(#include):文件包含命令把指定头文件插入该命令行位置取代该命令行,从而把指定的文件和当前的源程序文件连成一个源文件。
(3)条件编译(#ifdef):一般情况下,源程序中所有的行都参加编译。但有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。条件编译功能可按不同的条件去编译不同的程序部分,从而产生不同的目标代码文件。这对于程序的移植和调试是很有用的。

汇编阶段直接生成了汇编代码,具体过程不用赘述

链接器阶段则非常复杂,这里只简要叙述下主要的任务
(1)函数重载:c++编译器为实现函数重载普遍使用的是名字改编的方式为每个函数生成一个独一无二的名字,链接的时候就能找到正确的重载版本
(2)inline函数:如果函数体不太大,对此函数的所有调用都以函数本体去替代,注意inline只是对编译器的一个建议申请,不是强制命令
(3)模板处理:函数定义(包括具现化后的函数模板,类模板的成员函数),变量定义(包括函数模板的静态数据变量,类模板的静态数据变量,类模板的全局对象等)
(4)虚函数:每一个多态class都有一份虚函数表,定义或继承了虚函数的对象会有一个隐含成员:指向虚表的指针vptr,在构造或析构对象的时候,编译器生成的代码会修改这个指针。按道理说,一个多态class的虚表应该恰好被一个目标文件定义,这样链接就不会有错,但c++编译器有时无法判断是否应该在当前编译单元生成虚表定义,为保险起见,只能每个编译单元都生成虚表,然后交给链接器来消除重复数据。

c++使用的也是c语言的单遍编译的方式,意思就是从头到尾扫描一遍源码,一边解析源码,一边即刻生成目标代码,这么做的原因是:编译器没办法在内存里完整的表示单个源文件的抽象语法树,更不可能把整个程序(由多个源文件组成)放进内存里,以完成交叉引用(不同源文件的函数相互调用,使用外部变量等)

你可能感兴趣的:(c++学习)