基础回顾:c/c++编译过程

C/C++的编译过程基本相同,主要包括预处理、编译、汇编和链接四个阶段。下面通过gcc演示

1.预处理

预处理阶段是编译过程的第一步,主要处理源代码中的预处理器指令。这个阶段主要完成以下任务:

  1. 文件包含:

    处理 #include 指令,将被包含文件的内容直接插入到当前文件中。例如:#include <stdio.h> 会被替换为 stdio.h 的实际内容
  2. 宏展开:

    展开所有的宏定义,处理 #define 指令定义的宏。例如:#define MAX 100 会将代码中所有的 MAX 替换为 100
  3. 条件编译:

    处理条件编译指令,如 #if, #ifdef, #ifndef, #else, #elif, #endif,根据条件选择性地包含或排除某些代码段
  4. 删除注释:

    移除代码中的所有注释,包括单行注释 (//) 和多行注释 (/* */)
  5. 行控制:

    处理 #line 指令,可以修改编译器的行号计数和当前文件名
  6. 错误和警告:

    处理 #error 和 #warning 指令,生成编译错误或警告信息
  7. 特殊符号处理:

    处理预定义的特殊符号,如 FILELINEDATETIME 等这些符号会被替换为相应的值
  8. 头文件保护:

    处理头文件中的include保护符(通常使用 #ifndef, #define, #endif),防止同一个头文件被多次包含
  9. Pragma 指令:

    处理 #pragma 指令,这些指令通常用于控制编译器的行为
  10. 三元字符组替换:

    将某些特殊的字符序列替换为单个字符。例如:"??" 可能被替换为 "^"
  11. 连接相邻的字符串字面量:

    将源代码中相邻的字符串字面量合并为一个
  • 输入文件: .cpp, .cxx, .cc 等
  • 输出文件: .i
  • 例如: myfile.cpp -> myfile.i
g++ -E myfile.cpp > myfile.i

2.编译

编译阶段是将预处理后的源代码转换为汇编代码的过程。

  1. 词法分析:将源代码分解成一系列的标记,识别关键字、标识符、常量、运算符等

  2. 语法分析:根据语言的语法规则,将标记组织成抽象语法树检查代码是否符合语言的语法规则

  3. 语义分析:检查代码的语义正确性,类型检查,变量声明和使用检查,函数调用参数检查

  4. 中间代码生成:将AST转换为中间表示,如三地址码或四元式这种表示更接近机器码,但仍然与具体的机器架构无关

  5. 代码优化:对中间代码进行优化,以提高效率,常见优化包括:常量折叠、死代码消除、循环优化、内联展开等

  6. 目标代码生成:将优化后的中间代码转换为目标机器的汇编代码,这一步骤与具体的目标架构相关

  7. 符号表管理:维护一个符号表,记录变量、函数等标识符的信息。用于类型检查、作用域分析等

  8. 错误处理和诊断:检测并报告编译错误,生成警告信息

  9. 调试信息生成:如果启用了调试选项,生成调试信息(如行号对应关系)

  10. 特定语言特性处理:对于C++,还包括模板实例化、名称修饰(name mangling)等

  11. 内存布局决策:决定变量和数据结构在内存中的布局

  12. 寄存器分配:决定哪些变量放在寄存器中,哪些放在内存中

输出:

  • 编译阶段的最终输出通常是汇编代码(.s文件)
g++ -S myfile.i > myfile.s

3.汇编

汇编阶段是将编译器生成的汇编代码转换为机器码的过程。

  1. 指令转换:

    将汇编指令转换为对应的机器码,每条汇编指令通常对应一个或多个机器指令
  2. 符号解析:

    将汇编代码中的符号(如标签、变量名)转换为内存地址,对于外部符号(如来自其他模块的函数),生成重定位信息
  3. 地址分配:

    为代码和数据分配内存地址,这些地址可能是相对的,需要在链接阶段进行最终调整
  4. 生成目标文件:

    创建目标文件(.o 或 .obj),包含机器码、数据和元数据,目标文件通常包含多个段(section),如代码段、数据段、只读数据段等
  5. 生成重定位表:

    记录需要在链接阶段进行地址调整的位置
  6. 生成符号表:

    创建一个符号表,列出所有定义和引用的符号,包括全局符号、局部符号、外部符号等
  7. 常量池处理:

    将常量数据放入特定的段中
  8. 调试信息处理:

    如果启用了调试选项,将调试信息嵌入到目标文件中
  9. 错误检查:

    检查汇编代码中的语法错误,验证指令的合法性
  10. 架构特定优化:

    可能进行一些特定于目标架构的优化
  11. 生成元数据:

    包括目标文件格式信息、版本信息等

输出:

  • 汇编阶段的输出是目标文件(.o 或 .obj)
g++ -c myfile.s > myfile.o

链接

链接阶段是编译过程的最后一步,它将多个目标文件和库文件组合在一起,生成最终的可执行文件或共享库。

  1. 符号解析:

    解析所有外部符号引用,将每个符号引用与其定义匹配,检查是否有未解析的符号
  2. 地址和空间分配:

    为每个段分配内存地址,合并相同类型的段,确定每个符号的最终内存地址
  3. 重定位:

    调整代码和数据中的地址引用,用符号的实际地址替换占位符地址
  4. 库链接:

    链接静态库(.a 或 .lib 文件),为动态库(.so 或 .dll 文件)添加必要的信息
  5. 生成启动代码:

    添加程序入口点代码(如 main 函数的调用准备),添加初始化代码(如全局对象的构造函数调用)
  6. 解决名称修饰:

    特别是在C++中,处理由于函数重载等特性导致的复杂符号名
  7. 处理弱符号:

    解决多重定义的弱符号
  8. 生成导出和导入表:

    对于动态链接,生成必要的导出和导入信息
  9. 优化:

    可能进行一些全局优化,如删除未使用的代码和数据
  10. 生成元数据:

    添加程序头、节头等元数据,包含调试信息
  11. 错误检查:

    检查符号冲突,验证所有必需的符号都已解析
  12. 生成可执行文件:

    创建最终的可执行文件或共享库,设置正确的文件格式

输出:

  • 链接阶段的输出通常是可执行文件(在Unix/Linux系统上没有扩展名,在Windows上是.exe)或共享库(.so 或 .dll)
g++ myfile.o -o myfile

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值