编译——链接

简介: 编译——链接

ANSI C的任何一种实现中,存在两个不同的环境:

       第一种就是编译环境,在这个环境中源代码被转换成可执行的机器指令(二进制指令)

       第二种是执行环境,它用于实现执行代码

翻译环境

       其实翻译环境就是指编译和链接两个大的过程,而编译又可以分解成:预处理、编译、汇编三个过程。

       对于一个C语言的项目,可能有多个.c 文件,而多个.c文件有如何通过扁你链接生成可执行程序的呢?

  • 多个.c文件单独经过编译器,编译处理生成对应的目标文件
  • 在windows环境下目标文件的后缀是.obj ,在Linux环境下目标文件的后缀是.o  
  • 多个目标文件和链接库一起经过连接器处理生成最终的可执行程序
  • 链接库是指运行时库(它是支持程序运行的基本函数集合)

以gcc为例,拆解编译链接的过程

预编译(预处理):

       在预处理阶段,源文件和头文件会被处理形成 .i 为后缀的文件

在gcc环境下观察一下,对test.c文件预处理后的 .i 文件,命令如下:

 

gcc -E test.c -o test.i

       预处理阶段主要处理那些源文件中 # 开始的预编译指令。例如:#include ,#define处理规则如下:

  • 将所有的 #include 删除,并展开所有的宏定义
  • 处理所有的文件编译指令,如: #if 、#ifdef、#elif、#else、#end if
  • 处理所有的#include 预编译指令,将包含的头文件内容插入到该预编译指令的位置。这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件
  • 删除所有注释
  • 添加行号和文件名标识,方便后续编译器生成调试信息
  • 或保留所有的#pragma 编译器指令,编译器后续会使用

经过预处理后 .i 文件中就没有了宏定义(宏已经被展开)。包含的头文件也被插入到 .i文件中。所以我们无法知道宏的定义或者头文件包含是包含正确时,可以查看预处理之和的 .i文件来确认。

编译:

       编译过程就是将预处理之后的文件进行一系列的:词法分析、语法分析、语义分析及优化,生成相对应的汇编代码文件

编译过程的命令如下:

gcc -S test.i -o test.s

假设有以下代码,进行编译时,会怎么做呢:

 

array[index] = (index+4)*(2+6);

       词法分析:

       将源代码程序输入扫描器,扫描器的任务就是简单的进行词法分析,将代码中的字符分割成一系列的记号(关键字、标识符、字面量、特殊字符等)

对上述代码就行此法分析:

      语法分析:

语法分析就是对扫描产生的记号进行语法分析,从而产生语法树。这些语法树是以表达式为节点的树。

      语义分析:

由语义编译器来完成语义分析,即对表达式的语法层面进行分析。编译器所能做的分析就是语义的静态分析。静态语义分析通常包括声明和类型的匹配,类型的转换等。这个阶段会报告错误的语法信息。

汇编:

汇编器是将汇编代码转变成机器可执行的指令,每一个汇编语句几乎都对应一条机器指令。就是根据汇编指令对机器指令的对照表一一对应的进行翻译,而不做指令优化

汇编的命令如下

gcc -c test.s -o test.o

链接:

链接是一个十分复杂的过程,链接的时候需要把一堆文件链接在一起才生成可执行程序

链接的过程主要包括:地址和空间的分配、符号决议和重定位

链接解决的就是一个项目多个文件、多模块之间相互调用的问题

例如:在一个项目总有两个.c文件(test.c和add.c)

test.c

#define _CRT_SECURE_NO_WARNINGS
 
#include<stdio.h>
extern Add(int x, int y);
//声明外部函数
 
extern int years;
//声明外部变量
 
int main() {
  int x, y;
  scanf("%d%d", &x, &y);
  printf("%d\n", Add(x, y));
  printf("%d\n", years);
  return 0;
}

add.c

int years = 2024;
 
int Add(int x, int y)
{
  return x + y;
}

我们知道,每一个源文件都会单独经过编译器处理生成对应的目标文件

test.c经过编译器处理生成 test.o

add.c经过编译器处理生成 add.o

在test.c 我文件中使用了add.c文件的Add函数和years变量;

       在test.c文件中每一次使用Add函数和years变量时必须知道Add函数和years变量的地址,但是每一个文件都是单独编译的,在编译器编译test.c的时候并不知道Add函数和years变量的地址,所以就暂时把调用Add的指令和目标的地址和years的地址搁置。等待最后链接的时候由链接器根据引用的符号Add在其他模块中查找Add函数的地址,然后将test.c中所有引用到Add函数的指令进行重新修正,让他们目标地址变成真正的Add函数的地址,对于全局的变量也是类似的方法来修正地址。这个地址修正的过程也被叫做:重定位。

       编译链接是一个十分复杂的过程,这里简单讲解以下大概过程,感兴趣可以看《程序员的自我修养》一书来详细了解

执行环境

  1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统来完成。在独立的环境中,程序的载入必须手工安排,也可能是通过可执行代码置入只读内存来完成。
  2. 程序的执行便开始,接着便调用main函数。
  3. 开始执行程序代码,这时候程序会使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留它们的值。
  4. 终止程序,正常终止main函数;也可能意外终止。
相关文章
|
24天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
16天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
20天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2577 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
18天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
3天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
2天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
163 2
|
20天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1576 16
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
22天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
977 14
|
4天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
221 2
|
17天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
734 9