新闻详情

新闻详情

首页 / 资讯中心 / 详情

编译链接的过程发生了什么?

发布时间:2026/11/14 6:22:02来源:尧图网络
编译链接的过程发生了什么?
目录摘要一翻译环境和执行环境二翻译环境工作图三翻译环境工作的展示第一阶段预编译第二阶段编译第三阶段汇编第四阶段链接四链接的功能讲解五模版函数的分离编译摘要文讲解 C 程序的翻译与执行过程包括翻译环境与执行环境、翻译环境工作图以及预编译、编译、汇编、链接四个阶段的具体工作。文章还专门讲解了链接的功能并深入分析了模板函数的分离编译问题——为什么模板声明与定义分离会导致链接错误以及如何解决。一翻译环境和执行环境在ANSI C的任何一种实现中存在两个不同的环境。第1种是翻译环境在这个环境中源代码被转换为可执⾏的机器指令⼆进制指令。第2种是执⾏环境它⽤于实际执⾏代码。也就是说↓1翻译环境代码-二进制指令2执行环境执行二进制指令❓️我们写的代码是文本信息而计算机执行的是二进制的指令这二者之间如何进行的转换换句话说就是翻译环境中发生了什么才让代码-二进制指令如下图解释我们写代码的文件叫作.c源文件会经过编译器生成目标文件不同环境和编译器的目标文件不同比如VS是.obj,Linux环境下的gcc是.o最后通过链接器把生成的目标文件和链接库进行链接生成可执行程序。二翻译环境工作图VS上从写代码到生成可执行程序的过程编译器隐式得为我们做了太多事情才让我们能从.c(源文件)一下到.obj(目标文件)所以为了逐步展示翻译环境中的细节博主选择在Linux环境下的gcc编译器下进行细节上的演示~翻译环境分为四步①预编译也叫作预处理②编译③汇编④链接三翻译环境工作的展示前提准备源文件创建及代码书写我们在gcc中创建一个class110目录在其下创建一个源文件test.c在里面写上如图所示的代码第一阶段预编译首先在终端对我们上面创建的test.c这个源文件进行gcc -E -o test.igcc -E -o test.i的意义执行完预编译阶段就停止然后把内容放在test.i这个文件此时生成了test.i这个文件test.i文件内容如下将test.i和test.c进行对比解释将test.i和test.c进行对比我们就能发现了第一阶段预编译的作用①注释的删除②头文件的包含test.i前面的800行就是#includestdio.h的内容③#define符号的替换直接把M替换成了100④综上所示整个翻译环境是不对.h文件进行处理.h文件是在被包含的源文件进行到预编译这一步时才会去展开总结所有的预处理指令如文件包含、宏定义、条件编译等都是在预编译阶段完成的这些统称为文本操作第二阶段编译解释①首先进行gcc -S test.igcc -S test.i的意义对test.i执行完第二阶段编译就停止内容放进自动生成的test.s中②此时打开test.s发现全是汇编代码 所以编译阶段的工作是将代码翻译成汇编代码放进了自动生成的test.s中第三阶段汇编首先进行gcc -c test.cgcc -c test.c意义为test.c执行完第三阶段汇编就停止放进自动生成的目标文件test.o中然后试图打开test.o被警告因为test.o是二进制文件无法被直接打开所以汇编阶段的功能将汇编指令翻译成了二进制指令强行打开目标文件test.o注ELF是一种文件的格式 需要用指令readelf来读取ELF格式的文件所以我们用指令readelf来读取ELF格式的文件此时发现我们需要输入一些选项-a,-h,-l.......来进行选择性的查看我们使用-a选项即可查看到段表如下解释这就是段表也就是说ELF这种文件格式其实是按照一个一个的段来存储的这也是第四阶段链接中的功能合并段表中所谓的段表也可以-s来查看符号表解释①此时发现符号表中有我们代码的全局变量g_val函数Add函数main库函数printf②这些都被存储到了符号表中 这就是第三阶段汇编的另一个作用形成符号表那么符号表是做什么的在第四阶段里面有作用第四阶段链接如上进行gcc test.o -0 test 即可链接生成可执行程序test然后尝试打开可执行程序test但无法打开因为可执行程序test经过链接之后依旧还是二进制文件所以要想打开用ELF即可四链接的功能讲解假设现在有两个.c源文件解释一个.c只是声明了Add函数一个.c有函数的定义所以链接的功能如下图解释①每个源文件都在编译阶段进行了符号汇总在汇编阶段进行了形成符号表即函数和对应的地址进行合并形成符号表②但是对于test.c中这种仅有声明的函数我们将其地址暂且存为0x0000等到链接的时候与其他的.obj或.0目标文件(.c文件经过预编译编译汇编得到的目标文件)的符号表进行所以就在add.c对应的add.o目标文件中找到了add函数的确切地址完善了add函数对应的符号③Add的地址确认为有效地址add.c中的函数地址就叫作符号表的重定位所以经过链接这一步才能使用函数定义在另一个文件的函数还有其他库中的函数也需要链接这一步才能找到五模版函数的分离编译链接的本质就是通过符号表的合并和符号表的重定义得到各种函数真实的地址从而才能让一个源文件中所涉及到的函数被找到调用❓️但是了解过C模版函数的朋友都知道模版函数是不支持声明(.h)和定义(.cpp)分开文件放的为什么呢解释如下普通函数不管你是否声明定义分离起码最后通过链接就可以得到函数的准确地址但是模版函数即使通过了链接也得不到模版函数的准确地址因为模版函数需要用户给他传递模版参数其才可以实例化出具体的函数才可以生成具体的函数地址模板函数如果没有被实例化编译期就不会生成该模版函数对应的符号于是链接器根本找不到这个符号也就得不到对应的函数地址❓️我们的main中不是在调用模版函数时传递了具体参数吗为什么不会实例化呢前文中的Add.c文件中有着Add函数的定义此时编译器检测到该文件存在非模版函数Add编译器就会无条件为Add函数生成对应符号但是若Add.存放的是模版函数则编译器会无视掉不为其生成对应符号这就是为什么模版函数在经过链接之后仍然找不到函数地址这和你在main中调用模版函数时传递了具体参数无关❓️为什么编译器要这么做呢像对待普通函数一样对待模版函数不行吗因为如果编译器这么做了假设现在有100个文件调用了该模版函数则编译器需要读取100个文件才知道每个文件调用该模板函数时传递的模版类型是什么然后再去Add.c对其中的模板函数分别传递100次类型从而实例化出对应函数生成函数地址太麻烦了影响效率所以编译器不这么做C直接规定模版函数的声明定义不能分离必须写在同一个文件中使用但总有情况使得模版函数不易分离此时还有另一种办法文件 1func.h#pragma once templateclass T T Add(const T a, const T b); // 只有声明文件 2func.cpp#include func.h templateclass T T Add(const T a, const T b) // 定义 { return a b; } // 显式实例化只生成 int 版 template int Addint(const int, const int);文件 3main.cpp#include iostream #include func.h using namespace std; int main() { cout Add(1, 2) endl; // ① Addint → func.cpp 已实例化 → ✅ cout Add(1.5, 2.5) endl; // ② Adddouble → func.cpp 没实例化 → ❌ return 0; }解释①在模版函数定义的文件中进行显式实例化比如让其只能实例化为int其实就是将这个模版函数伪造成了一个类型为int的非模板函数②缺点就在于下次你想传递模版参数为double调用该模板函数就不适用了需要手动将显式实例化的代码改成double这就是显式实例化的硬伤。所以模版函数的声明定义放在一起才是最正确最简单最严谨的做法 [ 作者 ] shylyly [ 首次发布 ] 2024.10.8❌ [ 最新修改 ] 2026.9.28 [ 声明 ] 由于笔者水平有限文中难免有疏漏或不妥之处还望读者不吝赐教
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

【外设】之大彩串口显示屏 2026/11/14 3:51:47

【外设】之大彩串口显示屏

大彩串口屏初步使用 1 .官网下载 STM32 屏幕 GUI 设计资料 http://www.gz-dc.com/category/typeid/4112 找到 STM32 Keil 工程,移植相关代码因项目而异进行移植,由于项目简单,本人只对用到的指令接口进行修改。 比如:注意事项&…

阅读更多 →
无法下载Windows系统iso文件 2026/11/12 23:59:09

无法下载Windows系统iso文件

当我遇到这个问题的时候,我打开了一个网站: 登录 然后我打算下载的时候: 突然那个官方的连接就可以下载了:

阅读更多 →
【清华代码熊】DeepSeek V4.1 Flash 后训练详解 2026/11/13 10:09:00

【清华代码熊】DeepSeek V4.1 Flash 后训练详解

📌 上期解析了 DeepSeek V4.1 Flash 模型架构改进,本期解析 DeepSeek V4.1 Flash 预训练/后训练技术: 🌟 预训练:45T 文本 多模态混合语料、直接训练 sparse attention(取消 DeepSeek V4 的 dense 冷启动&…

阅读更多 →
Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ... 2026/11/13 13:31:48

Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ...

文章主要内容和创新点 主要内容 本文聚焦于多模态大语言模型(MLLM)强化学习(RL)训练中的效率问题,提出了一个名为Shuffle-R1的框架。研究发现,当前RL训练存在两个关键缺陷: 优势值坍缩(Advantage Collapsing):批次中大多数优势值集中在零附近,导致有效梯度信号被淹…

阅读更多 →
PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction 2026/11/13 16:11:45

PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction

一、文章主要内容总结 本文聚焦于利用大型语言模型(LLMs)实现个人身份信息(PII)脱敏的研究,旨在解决传统脱敏方法(如基于规则的系统、领域特定命名实体识别(NER)模型)泛化能力差、跨格式/跨语境适应性弱的问题。 研究通过全面评估多种LLM架构(包括密集型LLM(D-LLM…

阅读更多 →
LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model 2026/11/14 3:51:43

LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model

文章主要内容和创新点 主要内容 本文聚焦于二进制图像-文本相关性评估任务(判断图像与文本“相关”或“不相关”),针对该任务中文本格式多样、相关性定义随场景变化等挑战,提出了基于多模态大语言模型(MLLM)的解决方案LLaVA-RE。 模型设计:LLaVA-RE基于LLaVA 1.5架构,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉