美文网首页
C++的编译总结

C++的编译总结

作者: Jowney | 来源:发表于2018-11-09 17:17 被阅读12次

    一、C++编译过程概述

    简化版流程

    不管是Linux系统还是Windows系统,C++源文件的编译流程都是一样的,只是编译过程中产生的过度文件的格式不一样,但作用大致相同。Linux系统下生成的目标文件是.o文件,Windows系统下生成的目标文件是.obj文件

    1) 编译单元

    首先要搞清楚编译单元和它的特点。
    简单来说一个cpp文件就是一个编译单元,头文件不用被编译。我们把所有的函数声明全部放进一个头文件中,当.cpp文件被编译时,它们就可以通过一个宏命令 “#include”包含进这个.cpp文件中,从而把它们的内容合并到.cpp文件中去,从而形成一个含有所有 必要信息的单个源文件,这个源文件就是一个编译单元。

    事实上编译每个编译单元(.cpp)时是相互独立的,即每个cpp文件之间是不知道对方的存在的(不考虑#include “xxx.cpp" 这种奇葩的写法)

    编译器会分别将每个编译单元 .cpp 进行编译,生成相应的.obj \ .o文件(下文会仔细介绍这两钟文件)

    然后链接器会将所有的.obj \ .o文件进行链接,生成最终可执行文件。

    2) 预编译(预处理)

    • C++的预处理是指在C++程序源代码被编译之前,由预处理器对C++程序源代码进行的处理。这个过程并不对程序的源代码进行解析。
      这里的预处理器(preprocessor)是指真正的编译开始之前由编译器调用的一个独立程序。

    • ↓↓↓↓↓预处理器主要负责以下的几处↓↓↓↓↓↓
      1.将所有的#define删除,并展开所有的宏定义;
      2.处理所有的预编译指令,例如:#if,#elif,#else,#endif;
      3.处理#include预编译指令,将被包含的文件插入到预编译指令的位置;
      4.添加行号信息文件名信息,便于调试;
      5.删除所有的注释;
      6.保留所有的#pragma编译指令,因为在编写程序的时候,我们经常要用到#pragma指令来设定编译器的状态

    3) 编译

    • ↓↓↓↓↓编译器主要负责以下的几处↓↓↓↓↓↓
      1.扫描,语法分析,语义分析,源代码优化,目标代码生成,目标代码优化;
      2.生成汇编代码;

    4) 汇编

    • ↓↓↓↓↓汇编器主要负责以下的几处↓↓↓↓↓↓
      1.根据汇编指令和特定平台,把汇编指令翻译成二进制机器指令;
      2.生成目标文件(.o文件或者.obj);
    • 重要知识点:.o或者.obj文件内部至少要有3张表
      1.导出符号表: 即该目标文件可以提供的符号及地址
      2.未解决符号表:即找不到地址的符号的列表,告诉链接器这些符号没找到地址
      3.地址重定向表:链接的时候,链接器会为目标文件的“未解决符号表”里的符号在其他目标文件中寻找地址,但是每个目标文件的地址都是从0x0000开始的,这样直接将对方文件中符号的地址拿过来用显然会是不正确的,为了区分不同的文件,链接器在链接时就会对每个目标文件的地址进行调整。
    • 总结:也就是说在编译一个编译单元(.cpp)生成相应的obj或o文件过程中编译器会将这个编译单元(.cpp)所能提供给其他编译单元(.cpp)使用的函数,变量定义记录下来。而将自己缺少的函数,变量的定义也记录下来。
    • 例子


      a.cpp
      b.cpp
    生成对应的目标文件

    然后在链接器连接的时候就会知道a.obj需要show函数定义,而b.obj中恰好提供了show函数的定义,通过链接,在最终的可执行文件中我们能看到show函数的运行。

    5) 链接

    链接程序的主要工作就是将有关的目标文件(库文件、.obj文件)彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。

    如图:最后一个是链接器 不是 连接器写错

    详细版流程图

    相关文章

      网友评论

          本文标题:C++的编译总结

          本文链接:https://www.haomeiwen.com/subject/vpzgxqtx.html