【C++学习入门】 1. 编译

以下内容由chatgpt生成

当我们写好了一个 C++ 程序并要运行时,需要经过编译、链接两个过程。C++ 编译器把程序转换成目标代码,在链接器的帮助下把目标代码与库程序合并起来。

下面我将详细解释 C++ 编译链接过程和原理。

编译

编译(Compiling)是把源代码转换为机器码(目标代码)的过程。通常包含以下步骤:

预处理

预处理器(EXP: gcc -E xxx.cpp),它主要是对源码进行宏处理,并把包含的头文件展开成实际的代码。预处理后,生成一个新的中间文件。

举例说明:

// a.h
#define MAX 100

// main.cpp
#include "a.h"

int main()
{
    int array[MAX];
    return 0;
}

进行预处理后,main.cpp 的内容会变成这样:

int main()
{
    int array[100];
    return 0;
}

编译

编译器将源代码编译成目标代码,也就是汇编语言代码(EXP: g++ -S xxx.cpp)。在编译器把源文件编译成汇编文件时,需要经过以下步骤:

  1. 词法分析(Lexical Analysis):将代码进行分词。

  2. 语法分析(Syntax Analysis):分析分词后的结果是否符合语法规则。如果有错误,就报告错误。

  3. 语义分析(Semantic Analysis):对程序进行分析并确定类型、范围等。如果有错误,就报告错误。

  4. 优化代码(Code Optimization):将程序进行优化,使其更加高效。

  5. 生成目标代码(Code Generation):把汇编码生成目标代码。

汇编代码大致如下:

main:
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $400, %rsp
    movl    $0, -4(%rbp)
    movl    $0, %eax
    leave
    ret

汇编

编译器编译后生成汇编代码,然后通过汇编器将汇编代码转换成机器码(EXP: g++ -c xxx.cpp),这个过程包含以下步骤:

  1. 把汇编代码分割成多个可重定位的部分(机器码、数据、符号表、重定向表等)。

  2. 把指定的汇编代码转成机器码。

  3. 把数据添加到可重定位部分。

  4. 把符号和重定位引用添加到部分符号表和重定位表中。

  5. 把可重定位部分放入目标文件中。

目标文件包含头文件、段区域等。

链接

链接器(Linking)是把多个可重定位的目标文件和库文件链接成一个完整的可执行程序。链接的过程可以分为如下步骤:

  1. 符号重定向

每个目标文件中都有定义的符号和引用的符号,链接器需要把所有符号定义和引用都关联起来。

链接器会扫描所有目标文件,收集代码中所有的符号(就是变量名和函数名等),并将他们记录到符号表中。如果一个目标文件中定义了一个符号,而另一个目标文件中引用了同名符号,那么这就产生了一个未定义符号错误。符号重定向解决了这个问题。重定向指令就是告诉链接器具体的地址。

  1. 合并代码

用符号表把所有目标文件进行关联,进而生成一个.unalligned的程序,这个程序并不能被直接调用。

  1. 地址重分配

链接器会分配代码中所需的内存地址,并将它们所有的修复地方的地址都替换成实际的地址,将代码与所需要的库函数重定向生成最终的可执行文件。

  1. 检查

最后链接器会检查可执行文件的完整性,确保所有的符号都有定义。当程序需要调用一个函数或使用一个变量时,链接器就会检查程序中是否存在这个函数或变量。

  1. 生成可执行程序

链接器将产生一个可执行文件或一个动态链接库。如果生成的是可执行程序,那么可执行文件就可以直接被操作系统载入内存中运行,如果生成的是动态链接库,那么它就可以被多个程序共享,节约内存空间。

综上所述,编译链接的整个过程是比较复杂的,编译器也在不断地优化。掌握整个过程并了解原理,有助于我们做到更好地代码调试和程序优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值