• Windows系统下C++程序从源程序到可执行文件的4个阶段揭秘!(预处理、编译、汇编、链接)


    请添加图片描述

    • 🙋‍♂️ 作者:海码007
    • 📜 专栏:C++专栏
    • 💥 标题:【小白必看】Windows系统下C++程序从源程序到可执行文件的4个阶段揭秘!(预处理、编译、汇编、链接)
    • ❣️ 寄语:人生的意义或许可以发挥自己全部的潜力,所以加油吧!
    • 🎈 最后:文章作者技术和水平有限,如果文中出现错误,希望大家能指正

    0 引言

    在以前的代码编写阶段,只是知道源代码还有可执行文件.exe。并不是很清楚编译器工具是如何将源代码一步步变成可执行文件的。那么接下来就跟着我一起学习吧!

    首先简单介绍一下这些阶段所做的内容:

    1. 编写源代码:首先,程序员使用文本编辑器(如Notepad++、Visual Studio等)编写C++源代码文件。源代码是程序的初始形式,包含程序逻辑和功能的实现。
    2. 预处理(Preprocessing):在编译之前,源代码需要进行预处理。预处理器(如C预处理器)会处理源代码中的预处理指令,例如 #include 和 #define 等,以及删除注释。预处理的结果是一个经过宏展开和条件编译处理的新源代码文件。
    3. 编译(Compilation):编译器(如GNU C++编译器、Microsoft Visual C++编译器等)将预处理后的源代码转换为汇编语言。编译器会进行词法分析、语法分析和语义分析,并生成相应的汇编代码文件
    4. 汇编(Assembly):汇编器(如GNU汇编器)将汇编代码转换为机器码指令。汇编器会将汇编代码中的每条指令翻译为对应的机器码表示,并生成目标文件(通常是以 .obj或 .o为扩展名)
    5. 链接(Linking):链接器(如GNU链接器、MSVC链接器等)将目标文件与所需的库文件进行链接,生成最终的可执行文件。链接器的任务包括解析符号引用、符号重定位和地址重定位等。它会将程序所使用的函数和变量的引用与其定义进行匹配,并将所有必要的代码和数据组合在一起,生成一个完整的可执行文件。
    6. 可执行文件:最终生成的可执行文件包含了所有的程序代码和数据,以及操作系统所需的其他信息。它可以在Windows系统中直接运行,执行程序的功能和逻辑。

    在这里插入图片描述

    • 需要注意的是,这些阶段可能会有一些额外的步骤或优化过程,取决于使用的编译器和开发环境。此外,还可以在编译和链接过程中进行调试和优化操作,以提高程序的性能和稳定性。
    • 总结起来,C++程序在Windows系统下从源程序到可执行文件的主要阶段包括编写源代码、预处理、编译、汇编、链接和生成可执行文件。每个阶段都有特定的任务,通过这些阶段的处理,源代码最终被转换为计算机可以执行的机器码,实现了程序的功能和逻辑。

    1 预处理

    预处理阶段的任务

    1. 头文件包含:预处理器会处理源代码中的预处理指令,例如#include,将头文件的内容插入到源代码中。头文件通常包含了函数声明、宏定义、结构体和类的定义等。通过包含头文件,可以重用已经编写好的代码,并提供程序所需的各种声明和定义。
    2. 宏展开:预处理器会处理源代码中的宏定义(使用#define指令定义的宏),将宏展开为对应的代码片段。这样可以在代码中使用宏来代表一段固定的代码,提高代码的可读性和可维护性。
    3. 条件编译:预处理器可以根据条件编译指令(如#if、#ifdef、#ifndef、#elif、#else和#endif)来选择性地包含或排除部分代码。条件编译指令可以根据预定义的宏或平台相关的宏来决定编译哪些代码,从而实现跨平台编译或根据不同的情况编译不同的代码
    4. 注释删除:预处理器会删除源代码中的注释部分,包括行注释(//)和块注释(/* */),以及预处理器自身的注释(以#开头的行)。注释的删除可以提高编译过程的效率,并使得源代码更加清晰。
    5. 符号替换:预处理器会替换源代码中的预定义符号,例如__FILE__和__LINE__等。这些符号在预处理阶段被替换为对应的文件名和行号,用于调试和错误报告

    在这里插入图片描述

    2 编译

    C++程序编译的任务是将预处理后的源代码转换为汇编语言,并生成相应的汇编代码文件。编译器在这个阶段执行以下主要任务:

    1. 词法分析(Lexical Analysis):编译器首先对预处理后的源代码进行词法分析,将代码分解为一个个的词素(Token)。词素是代码中的最小语法单元,例如关键字、标识符、运算符和常量等。
    2. 语法分析(Syntax Analysis):编译器进行语法分析,根据编程语言的语法规则检查词法分析生成的词素序列是否符合语法规范。语法分析使用文法规则和语法树来确定代码的结构和组织方式。
    3. 语义分析(Semantic Analysis):编译器进行语义分析,检查代码中的语义错误和不一致性。语义分析器会验证词法和语法分析的结果,并对变量的声明和使用、函数调用等进行类型检查和语义规则的验证。
    4. 中间代码生成(Intermediate Code Generation):编译器生成中间代码,将源代码转换为一种与机器无关的中间表示形式。中间代码通常是一种抽象的计算模型,可以通过后续的优化和代码生成阶段转换为目标机器的汇编代码。
    5. 优化(Optimization):编译器进行代码优化,通过对中间代码进行分析和变换,改进程序的性能和效率。优化的目标是减少代码的执行时间、减少内存占用和提高程序的整体质量。
    6. 目标代码生成(Code Generation):编译器将优化后的中间代码转换为目标机器的汇编代码。目标代码生成器根据目标机器的特定指令集和内存模型,将中间代码映射为机器码指令序列。

    在这里插入图片描述

    3 链接

    在Windows操作系统下,C++代码链接阶段主要涉及以下任务:

    1. 符号解析(Symbol Resolution):在链接阶段,编译器会解析C++代码中使用的各种符号,例如函数名、变量名等。编译器会查找这些符号的定义,并建立符号与其定义之间的关联
    2. 符号重定位(Symbol Relocation):链接阶段还包括对代码和数据的符号重定位。在编译过程中,C++代码中使用的符号可能是相对于编译单元(对象文件)的位置,链接阶段需要将这些符号的引用地址重定位到最终生成的可执行文件的正确位置。
    3. 链接优化(Link-time Optimization):链接阶段也提供了机会进行一些针对整个程序的优化。通过在链接阶段对代码进行全局优化,编译器可以识别更多的优化机会,例如函数内联、循环展开等,以提高程序的性能
    4. 库文件链接(Library Linking):在链接阶段,编译器还会将程序中使用的外部库文件与可执行文件进行关联。这包括静态库动态库的链接过程。对于静态库,链接器会将库文件中的目标代码直接合并到可执行文件中。对于动态库,链接器会在可执行文件中创建对库文件的引用,以便在运行时动态加载。
    5. 生成可执行文件:链接阶段最终的任务是生成可执行文件。链接器将各个编译单元(对象文件)中的代码和数据进行整合,解析符号引用并进行重定位,最终生成可供操作系统执行的可执行文件。

    4 总结

    在这里插入图片描述


    在这里插入图片描述

    5 不同阶段有哪些关键字起作用?

    在C++中,各个阶段的关键字作用如下:

    1. 预处理阶段(Preprocessing Stage):

      • #include: 在预处理阶段将指定的头文件内容包含到当前文件中。
      • #define: 定义预处理宏。
      • #ifdef, #ifndef, #endif, #if, #else, #elif: 条件编译指令。
      • #pragma: 编译器特定的指令。
      • #error, #warning: 在编译过程中产生错误或警告信息。
    2. 编译阶段(Compilation Stage):

      • 所有C++关键字:例如int, class, if, for等,都在编译阶段起作用,编译器根据这些关键字进行语法解析、类型检查等操作。
      • 所有的标识符:包括变量名、函数名等。
    3. 汇编阶段(Assembly Stage):

      • 在汇编阶段,C++代码已经被转换为相应的汇编代码,因此与具体的C++关键字无关。在这个阶段,处理的是汇编指令、寄存器、内存地址等底层概念。
    4. 链接阶段(Linking Stage):

      • extern: 声明外部变量或函数。
      • static: 声明静态变量或函数。
      • inline: 内联函数。
      • template: 模板函数或类的实例化。
      • namespace: 命名空间。
      • 所有在不同编译单元中定义的变量和函数,以及它们的引用,都在链接阶段被解析和处理。
    5. 运行阶段(Runtime Stage):

      • new, delete: 在运行时进行动态内存分配和释放。
      • throw, try, catch: 异常处理机制。
      • 运行时类型识别(RTTI):如typeid操作符。
      • 类型转换运算符:如dynamic_cast, static_cast, reinterpret_cast, const_cast

    总之,C++中的关键字在不同的阶段起着不同的作用,从预处理、编译、汇编、链接到运行时阶段,各种关键字都发挥着不同的功能。

  • 相关阅读:
    由SoftRefLRUPolicyMSPerMB=0引起的频繁Full GC问题排查实战
    【刷题笔记10.6】LeetCode:翻转二叉树
    Admin.NET源码学习(3:LazyCaptcha使用浅析)
    加密市场进入寒冬,是“天灾”还是“人祸”?
    【JavaWeb - 网页编程】五 XML 介绍
    【力扣刷题练习】93. 复原 IP 地址
    基于ssm+vue设备配件检修管理系统
    SpringBoot整合Spring Security【超详细教程】
    【论文笔记】Deep Multi-View Spatial-Temporal Network for Taxi Demand Prediction
    2024/4/25 C++day3
  • 原文地址:https://blog.csdn.net/hhw_hhw/article/details/133656351