这里就拿cpp举例子。

c++程序编译过程

c++程序编译后生成的文件

  1. .exe :可执行文件,点击即可运行

  2. .ilk :当选定渐增型编译链接时,连接器自动生成ILK文件,记录链接信息

  3. .obj :目标文件,obj文件与cpp文件名字一一对应

  4. .pch :prcompiled-header,预编译头文件

  5. .idb :文件保存的信息,使编译器在重新编译的时候只重新编译改动过的函数和最新类定义改动过的源文件,这样可提高变异速度

  6. .pdb :Program Database,即程序数据库文件,用来记录调试信息

  7. .dsp :Developer Studio Project,配置文件

  8. .ncb :No Compile Browser,其中存放了供ClassView、WizardBar和Component Gallery使用的信息,由VC开发环境自动生成

  9. .plg :超文本文件,可以用IE打开,记录build的过程

  10. .cpp :C++源文件

C++程序编译过程

预处理(include define if ifdef pragma),编译,汇编,链接

编译 :把文本形式的源代码翻译成机器语言,并形成目标文件

连接 :把目标文件 操作系统的启动代码和库文件组织起来形成可执行程序

编译

//头文件,在编译之前读取
//预处理(include define if ifdef pragma),编译,汇编,链接
//#define FUCK int ,然后所有int=FUCK
//#if 0(bool=false)结尾加个#endif 那么中间代码就无效。因为if false
#include <iostream>  //阅读iostream然后复制到这里 这里有五万行代码。包含了iostream以及所有他引用的代码
void fuck(const char* message); //这里是声明fuck函数

//main函数。每个cpp都有一个main。main是程序的入口。
int main    //这里是main函数应该返回的是int,但是并没有返回int,因为main函数不一定要返回值,如果不返回值则默认返回了0
{         /*重载运算符,其实是一个函数,另一层含义是将字符串推送到cout流中 然后打印到终端,然后推一个行结束符告诉终端跳到下一行*/
    std::cout << "hello world!" <<  std::endl;   //计算机从这行开始执行代码
    
    std::cout.print("hello world!").print(std::endl);
    std::cin.get(); //这是等待我们按下enter。
}

细分为3个阶段:

  • 先进行编译预处理

预处理又称为预编译,是做些代码文本替换工作。编译器执行预处理指令(以#开头,例如#include),这个过程会得到不包含#指令的.i文件。这个过程会拷贝#include 包含的文件代码,进行#define 宏定义的替换 , 处理条件编译指令 (#ifndef #ifdef #endif)等。

  • 编译优化

通过预编译输出的.i文件中,只有常量:数字、字符串、变量的定义,以及c语言的关键字:main、if、else、for、while等。这阶段要做的工作主要是,通过语法分析和词法分析,确定所有指令是否符合规则,之后翻译成汇编代码。

这个过程将.i文件转化位.s文件。

  • 汇编

汇编过程就是把汇编语言翻译成目标机器指令的过程,生成目标文件(.obj .o等)。目标文件中存放的也就是与源程序等效的目标的机器语言代码。

目标文件由段组成,通常至少有两个段:

代码段:包换主要程序的指令。该段是可读和可执行的,一般不可写

数据段:存放程序用到的全局变量或静态数据。可读、可写、可执行。

这个过程将.s文件转化成.o文件。

连接过程

由汇编程序生成的目标文件并不能立即就执行,还要通过链接过程。

原因:

  • 某个源文件调用了另一个源文件中的函数或常量

  • 在程序中调用了某个库文件中的函数

链接程序的主要工作就是将有关的目标文件连接起来。

这个过程将.o文件转化成可执行的文件。

编译器以及链接器的报错速查指南

erro Cxxxx

compile 编译。C开头的代表编译过程错误。如语法错误,符号错误,未声明也未定义

一般是链接器找不到他要的东西。一下为具体场景

  1. 返回值不同,比如定义的是int,声明的是void

  2. 定义有两个值。但是调用的时候只输入了一个值。

  3. 有相同的函数名返回相同的值和相同的参数,因为连接器不知道连到哪个. {% label 注意 red %} #include很可能会导致这种情况。比如hello.h中包含a函数。有两个cpp文件都#include hello.h就会有这种情况。解决方法:

    1. 在hello.h的a函数前加static。原理如下

    2. 在a函数前加inline原理如下

    3. 将a函数放在要用的其中一个文件中。这样就不会include的到处都是。哈哈!没想到把!

    “重载”简单说来就是只要名字、参数、返回值有一个不一样,就相当于不同的函数

声明了函数但未定义

如果a函数光声明没定义,不调用a的话,那么不会报错。**但是!**如果a函数声明了但是没定义。然后b函数调用了a函数。即使没有在main中调用b,也会报错!!
因为编译器怕你会在其他地方调用了a函数。所以可以告诉编译器我们只会在这个文件中使用b函数:在b函数之前输入static(静态)意思是只在这个文件中声明b函数,那么编译器知道b函数只会出现在
这个翻译单元。 p8

总结

预编译处理(.c) -> 编译、优化程序(.i/.s)->汇编程序(.obj、.o、.a、.ko) -> 链接程序(.exe、.elf、.axf等)