C++编译器工作原理

从源代码到可执行文件

从源代码到可执行文件主要分:预处理、编译+汇编、静态链接 这三个过程
在这里插入图片描述

  • gcc HelloWorld.c -E -o HelloWorld.i 预处理:加入头文件,替换宏。
  • gcc HelloWorld.c -S -c -o HelloWorld.s 编译:包含预处理,将 C 程序转换成汇编程序。
  • gcc HelloWorld.c -c -o HelloWorld.o 汇编:包含预处理和编译,将汇编程序转换成可链接的二进制程序。
  • gcc HelloWorld.c -o HelloWorld 链接:包含以上所有操作,将可链接的二进制程序和其它别的库链接在一起,形成可执行的程序文件。

下面分别介绍下这三个过程:

预处理:

预处理过程主要处理源文件中的以“#”开始的预编译指令。包括#include,#define, #if等等
主要的处理规则如下:

  • 将所有的#define删除,并且展开所有的宏。
    如#define a b 就是将所有的a替换成b
  • 处理所有的条件预编译指令,,如#if,#ifdef,#else,#endif,以此来决定对哪些代码进行处理,将那些不必要的代码过滤掉
  • 处理#include预编译指令,将被包含的文件插入到该预编译指令的位置

编译+汇编

编译:
通过词法分析、语法分析、语义分析、源代码优化、类型检查等等,将源代码翻译成汇编代码。

汇编:
通过代码生成、目标代码优化等把汇编语言代码翻译成二进制机器码

编译+汇编示意图:
在这里插入图片描述

静态链接

前面的编译中,每个源代码模块是单独编译的,然而不同的模块之间不可避免地要相互引用变量或函数,这些变量或函数的地址只有在此阶段才能确定。链接过程就是把编译器生成的一个个目标文件链接成二进制可执行文件(.exe)

此阶段的链接是静态链接,运行期间的链接则是动态链接。
动态链接:静态链接期间不完成实际的链接操作,只保存函数的重定位信息,在运行期间才去找到动态库的函数符号进行重定位。

编译完成之后,运行:
“静态的程序”被载入内存,由 CPU 逐条语句执行,就形成了“动态的进程”。

静态库 vs 动态库

静态库

什么是静态库
静态库是指在应用中,有一些公共代码是需要反复使用,就把这些代码编译为库文件;在链接步骤中,链接器从库文件取得所需的代码,复制到生成的可执行文件中。

命名方式:
静态库的文件名命名方式是“libxxx.a”,库名前面加“lib”,windows和linux下后缀都用的是“.a”,“xxx”为静态库名。

链接时间:
编译过程中被载入程序

连接方式:
静态库的链接是将整个函数库的所有数据都整合进了目标代码。

优缺点:

  • 优点:可执行程序可以直接运行,不再需要外部函数库的支持,因为所有函数都已经被编进去了。运行效率较高。

  • 缺点:假如多个程序使用同一个静态库,等同于多段相同的代码分别保存在不同的可执行程序中,变相占用了更多的内存空间。而且如果所使用的静态库发生更新改变,你的程序必须重新编译。

动态库

什么是动态库
动态库就是编译程序时,可执行程序中只保存对应的函数的引用表,等到程序执行时,再链接对应的库。

命名方式:
动态库的命名方式与静态库类似,前缀相同为“lib”,linux下后缀名为“.so(shared object)”即libxxx.so;而windows 下后缀名为“.dll(dynamic link library)”即libxxx.dll.

链接时间和方式:
动态库在编译的时候并没有被编译进目标代码,而是当你的程序执行到相关函数时才调用该函数库里的相应函数。

优缺点:

  • 优点:多个可执行程序共用同一个库,节省内存。且动态库的改变并不影响 你的程序,所以动态函数库升级比较方便。

  • 缺点:因为函数库并没有整合进程序,所以程序的运行环境必须提供相应的库,运行可执行程序需要额外做一次链接操作,执行速度会相对慢一些

编译过程详解

在这里插入图片描述
更详细内容见:
编译的全过程都悄悄做了哪些事情?

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
gcc是一款开源的编译器,它可以将C、C++、Objective-C等高级语言的源代码转换成可执文件。gcc编译器工作原理可以分为四个阶段:预处理、编译、汇编和链接。 1. 预处理阶段:在这个阶段,gcc会对源代码进预处理,主要包括以下几个步骤: - 处理头文件:将#include指令所包含的头文件内容插入到源代码中。 - 宏替换:将源代码中的宏替换成宏定义所对应的内容。 - 条件编译:根据#if、#ifdef、#ifndef、#else、#elif和#endif指令来判断哪些代码需要编译,哪些代码需要忽略。 - 去注释:将源代码中的注释删除。 2. 编译阶段:在这个阶段,gcc会将预处理后的源代码转换成汇编代码,主要包括以下几个步骤: - 词法分析:将源代码分解成一个个单词。 - 语法分析:将单词组成语句,并检查语法是否正确。 - 语义分析:检查语句是否有意义,如变量是否定义过等。 - 中间代码生成:将源代码转换成中间代码。 3. 汇编阶段:在这个阶段,gcc会将汇编代码转换成机器码,主要包括以下几个步骤: - 语法分析:将汇编代码分解成指令和操作数。 - 语义分析:检查指令和操作数是否有意义。 - 目标代码生成:将汇编代码转换成目标代码。 4. 链接阶段:在这个阶段,gcc会将目标代码和库文件链接成可执文件,主要包括以下几个步骤: - 符号解析:将目标代码中的符号(如函数名、变量名等)与库文件中的符号进匹配。 - 重定位:将目标代码中的地址与库文件中的地址进匹配。 - 可执文件生成:将目标代码和库文件链接成可执文件。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值