• 详解C++代码从源代码到可执行文件的整个编译过程(预处理、编译、汇编和链接)


    C++代码从源代码到可执行文件的生成过程,通常包括以下四个阶段:预处理、编译、汇编和链接。每个阶段都有特定的任务和目标。

    1. 预处理 (Preprocessing)

    预处理阶段主要是处理以#开头的预处理指令,比如宏定义、文件包含和条件编译等。在这个阶段,预处理器(通常是cpp)会对代码进行以下操作:

    • 宏展开:将所有的宏定义用它们的值替换。例如,#define PI 3.14会替换所有出现的PI3.14
    • 文件包含:将#include指令引入的头文件内容直接插入到指令所在的位置。例如,#include 会被替换为iostream文件的内容。
    • 条件编译:根据条件编译指令(如#if#ifdef#ifndef等)的判断,选择性地包含或排除代码块。
    • 删除注释:去除源代码中的所有注释(///* */),以便在后续阶段不会被处理。

    预处理的输出是一个扩展后的纯C++代码文件,通常是一个临时文件。

    示例:

    1. #define PI 3.14
    2. #include
    3. int main() {
    4. std::cout << "Value of PI: " << PI << std::endl;
    5. return 0;
    6. }

    经过预处理,可能会生成类似于以下的代码:

    1. // 包含了iostream文件内容...
    2. int main() {
    3. std::cout << "Value of PI: " << 3.14 << std::endl;
    4. return 0;
    5. }

    2. 编译 (Compilation)

    编译阶段的目标是将预处理后的C++源代码转换为目标文件。这个过程包括语法分析、语义分析和代码生成。编译器(如g++clang++)会:

    • 语法分析:检查代码的语法是否正确,生成抽象语法树(AST)。
    • 语义分析:检查代码的类型和作用域等语义是否正确。
    • 中间代码生成:将语法树转换为中间表示(IR),例如LLVM IR或三地址代码。
    • 优化:对中间代码进行优化,以提升性能和减少代码大小。
    • 目标代码生成:将中间代码转换为特定机器的汇编代码。

    编译的输出是一个或多个汇编代码文件,通常以.s为扩展名。

    示例:

    1. int main() {
    2. int a = 5;
    3. int b = 10;
    4. int c = a + b;
    5. return 0;
    6. }
    '
    运行

    编译后,生成的汇编代码可能类似于以下内容:

    1. movl $5, -4(%rbp)
    2. movl $10, -8(%rbp)
    3. movl -4(%rbp), %eax
    4. addl -8(%rbp), %eax
    5. movl %eax, -12(%rbp)

    3. 汇编 (Assembly)

    在汇编阶段,汇编器(如as)将汇编代码转换为机器语言的二进制代码,即目标文件。目标文件包含了可执行代码和数据,但还不是完整的可执行文件,不能独立运行。

    汇编的输出是一个或多个目标文件,通常以.o.obj为扩展名。

    示例:

    1. movl $5, -4(%rbp)
    2. movl $10, -8(%rbp)
    3. movl -4(%rbp), %eax
    4. addl -8(%rbp), %eax
    5. movl %eax, -12(%rbp)

    汇编后,生成的目标文件是二进制格式,无法直接读取或理解。

    4. 链接 (Linking)

    链接阶段是将一个或多个目标文件和所需的库文件结合起来,生成最终的可执行文件。链接器(如ld)会:

    • 符号解析:解析所有的符号(函数和变量),确保每个符号都有定义且唯一。
    • 地址调整:将所有模块中的符号和地址重定位到最终的地址空间中。
    • 库链接:将静态库或动态库的代码与目标文件链接在一起。

    链接的输出是一个可执行文件,可以在操作系统上直接运行,通常没有扩展名或者是.exe(在Windows上)。

    示例:

    如果我们有两个目标文件main.outils.o,链接器会将它们合并,解析所有符号,生成最终的可执行文件main

    g++ main.o utils.o -o main
    

    整个编译过程可以总结为:预处理 -> 编译 -> 汇编 -> 链接。每个阶段都有其特定的任务和生成的中间文件,最终输出的是一个可执行文件。

  • 相关阅读:
    与时同行 “云寄 • 时光邮局”|我想开始一个有意思的项目!
    RabbitMQ之交换机
    常用的特征分析和特征工程
    【吴恩达L1W2作业2】有关scipy.misc.imresize
    房产交易软件开发
    自定义表单工具好用的优点是什么?
    Java设计模式之备忘录模式
    Java项目:ssm电影院购票系统
    SpringCloud Feign 远程调用(史上最详细讲解)
    服务器部署项目总结
  • 原文地址:https://blog.csdn.net/qq_44905692/article/details/140259228