C语言笔记第16篇:编译和链接

1、翻译环境和运行环境

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

第1种是翻译环境,在这个环境中源代码被转换为可执行机器指令(二进制指令)

第2种是执行环境,它用于实际执行代码

2、翻译环境

那翻译环境是怎么将源代码转换为可执行的机器指令的呢?这里我们就得展开讲解一下翻译环境所做的事情。

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

一个C语言的项目中可能有多个.c文件一起构建,那么多个.c文件如何生成可执行程序呢?

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

什么是链接库?

在学习C语言时我们经常会用到库函数,比如printf、scanf,这些函数肯定不是凭空出现的,像这样的库函数是被编译成一个一个的链接库,这些函数都包含在这个链接库中也就是第三方库,是C编译器厂商自己提供的库来供我们使用。在我们的C程序中会用到库函数,但是必须经过链接器目标文件和链接库一起链接才能调用该库函数。

举个例子:比如有一条河,两个人想见面,一个人(程序)在河的这边,而另一个人(库函数实现)在河的那边,那两人想见面(调用)是不是必须搭一座桥,而这座桥就是链接器。

其实还可以把编译器的编译展开成3个过程,那就变成了下面的过程:

Linux环境下:

2.1 预处理(预编译)

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

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

gcc -E test.c -o test.i

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

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

经过预处理后的.i文件中不再包含宏定义,因为宏已经被展开。并且包含的头文件都被插入到.i文件中,所以当我们无法知道宏定义或者头文件是否包含正确的时候,可以查看预处理后的.i文件来确认。

2.2 编译

编译过程就是将预处理后的文件进行一系列:词法分析语法分析语义分析、符号汇总(链接阶段会讲一下符号汇总有什么用)及优化,生成相应的汇编指令。简单来说编译过程就是将C语言代码转换成汇编代码。

编译过程的命令如下:

gcc -S test.i -o test.s

对下面代码进行编译的时候,会怎么做呢?假设有下面的代码:

array[index] = (index + 4) * (2 + 6);
2.2.1 词法分析

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

上面代码进行词法分析后得到了16个记号:

记号类型
array标识符
[左方括号
index标识符
]右方括号
=赋值
(左圆括号
index标识符
+加号
4数字
)右圆括号
*乘号
(左圆括号
2数字
+加号
6数字
)右圆括号
2.2.2 语法分析

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

2.2.3 语义分析

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

以上步骤完成后,最后就是将代码生成汇编指令,然后编译阶段就完成了。

2.3 汇编

汇编器是将汇编代码转变(翻译)为可执行的二进制指令,每一个汇编语言几乎都对应一条机器指令。就是根据汇编指令和机器指令的对照表一一的进行翻译,也不做指令优化。

注:这个过程还会形成符号表,是根据编译过程的符号汇总生成符号表的。

汇编的命令如下:

gcc -c test.s -o test.o

2.4 链接

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

链接过程主要包括:地址和空间分配,符号决议和重定位等这些步骤。

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

链接主要就是处理不同文件之间的相互调用,比如:

add.c

int g_val = 2023;
int Add(int x, int y)
{return x + y;
}

test.c

extern int Add(int x,int y);
extern int g_val;
int main()
{printf("%d\n",g_val);printf("%d\n",Add(2, 3));return 0;
}

这两个文件直接是如何链接的才可以相互调用的呢?

注意:这两个文件会生产目标文件:add.obj、test.obj,在生产目标文件之前的编译过程中会对两个文件进行符号汇总,然后在汇编过程中又会形成符号表。比如add.c文件在编译过程中会进行符号汇总:g_val、Add,test.c在编译过程中进行符号汇总:g_val、Add、main,下一步在汇编过程中每个文件汇总出的符号是会形成符号表的,符号表中每个符号都有对应的地址。

例如:add.obj符号表

符号地址
g_val0x100
Add0x200

test.obj符号表

符号地址
Add0x000(无效的地址)
g_val0x000(无效的地址)
main0x300

注:以上地址是自己填上去的,真正的地址不是这样,只是举个例子使用

test.c里的符号Add和g_val由于是外部声明符号,并不知道符号真实地址,所以形成符号表时就给个无效地址。

链接过程中这些符号表是要进行合并的,多个目标文件都是一个项目的,没必要那么多符号表,所以只需将多个文件的符号表合成一个就够了。

add.obj和test.obj经过链接合并成的符号表:

符号地址
Add0x200
g_val0x100
main0x300

因为合并时找到了符号本身的有效地址,多以合并时将无效地址替换掉了,最终两个文件的符号表合并在了一起,运行时便可以通过该符号表的地址找到对应符号并调用。

而合并符号表过程中将test.obj符号表中Add符号的无效地址或g_val符号的无效地址替换掉就叫做符号的决议和重定位

总结:

多个文件之间相互调用首先需要在编译阶段进行符号汇总,然后汇编阶段将汇总出的符号形成符号表,符号表中的每个符号都分配有对应地址。最后在链接阶段将多个目标文件的符号表进行符号表合并,至此多个文件的符号都有了联系,一个文件如果想调用另一个文件的函数就可以通过符号表的地址找到该函数并调用。

3、运行环境

1. 程序必须载入内存中,在有操作系统的环境中,一般这个由操作系统完成,程序的载入必须要手工安排,也可能是通过可执行代码置入只读内存完成。

2. 程序的指向便开始,接着便调用main函数。

3. 开始执行程序代码,这个时候程序将使用一个运行时堆栈(stack(函数栈帧)),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留它们的值。

4. 终止程序,正常终止main函数;也有可能是意外终止。

本篇C语言笔记第16篇:编译和链接 到了这里也就结束了,我们下一篇笔记再见-

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/29885.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据资产管理的未来趋势:洞察技术前沿,探讨数据资产管理在云计算、大数据、区块链等新技术下的发展趋势

一、引言 随着信息技术的飞速发展,数据已成为企业最重要的资产之一。数据资产管理作为企业核心竞争力的关键组成部分,其发展趋势和技术创新受到了广泛关注。特别是在云计算、大数据、区块链等新技术不断涌现的背景下,数据资产管理面临着前所…

【凤凰房产-注册安全分析报告-缺少轨迹的滑动条】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…

2024 端午节巽寮湾游玩记录

2024 端午节巽寮湾游玩记录 文章目录 2024 端午节巽寮湾游玩记录一、前言二、巽寮湾游玩行程1、三天衣食住行2、主要图片: 三、其他1、小结2、巽寮湾游玩建议3、感慨 一、前言 时间总是过得很快,只要你活着时间就会不停往前走。 所以你以后的路其实都是…

外卖APP开发详解:从同城O2O系统源码开始

近期,从事软件开发的小伙伴们都在讨论外卖APP,热度非常之高,所以小编今天将与大家一同探讨同城O2O系统源码、外卖APP开发。 一、外卖APP开发的前期准备 了解目标用户的需求,分析竞争对手的优劣势,明确自身的市场定位。…

如何在Vue3中处理异步API调用并更新表单数据(附Demo)

目录 前言1. 问题所示2. 知识分析3. 实战 前言 从实战问题中剖析知识点 1. 问题所示 执行Vue3数据的时候&#xff0c;终端输出的data如下所示 Promise {<pending>} [[Prototype]] : Promise [[PromiseState]] : "fulfilled" [[PromiseResult]] : Array(…

【Unity拖拽物体】实现对点中的3D物体进行拖拽的功能

场景结构&#xff0c;两个普通模型 第一种 脚本所挂载的物体才可以被拖拽 【PC鼠标版本】 using UnityEngine;// 这个脚本实现了&#xff0c;本脚本所在的游戏物体能够被拖拽 public class DragObjectT : MonoBehaviour {private Vector3 screenPoint; // 存储物体在屏幕上的位…

python GUI开发: tkinter菜单创建,记事本和画图软件综合项目的实战演练

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

百度智能云推出智能运维工具,云助手让云服务器运维更简单

为了提升云服务器执行命令的效率&#xff0c;百度智能云发布了 SmartTerm 远程连接终端。不止于此&#xff0c;为了更加极致地提升运维效率&#xff0c;我们又推出了「云助手」这款轻量快捷的运维工具。 ​ 只有做过云服务器运维的人才知道管理上万台云服务器有多崩溃。在海量…

了解振弦采集仪在建筑物安全监测中的应用与研究

了解振弦采集仪在建筑物安全监测中的应用与研究 摘要&#xff1a;河北稳控科技振弦采集仪是一种常用的结构物安全监测设备&#xff0c;广泛应用于建筑物、桥梁、塔楼等工程结构的监测。本文将从振弦采集仪的原理、应用案例和研究进展等方面进行详细介绍&#xff0c;以便更好地…

springboot3 基础特性(1)

文章目录 一、SpringApplication三种方式1.1 基础方式1.2.自定义 SpringApplication1.3、FluentBuilder API 二、自定义Banner三、Profiles3.1 什么是 Profiles &#xff1f;3.2 声明Profiles3.3 激活配置文件3.3.1 分组3.3.2 环境包含3.3.3 激活方式3.3.4 配置优先级 一、Spri…

STM32单片机USART串口详解

文章目录 1. 通信接口概述 2. 串口通信 3. 硬件电路 4. 电平标准 5. 串口参数及时序 5.1 数据帧的组成 5.2 起始位 5.3 数据位 5.4 校验位 5.5 停止位 5.6 波特率 5.7 数据帧传输过程示例 6. 串口时序 7. USART概述 8. USART框图 9. USART基本结构 10. 数据帧…

力扣793. 阶乘函数后 K 个零

Problem: 793. 阶乘函数后 K 个零 文章目录 题目描述思路即解法复杂度Code 题目描述 思路即解法 1.根据题意可知即是要求取满足条件的n最小是多少&#xff0c;最大是多少&#xff0c;最大值和最小值一减&#xff0c;就可以算出来有多少个n满足条件了。 2.由于题目中的阶乘存在单…

乡村养老服务管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;医疗人员管理&#xff0c;乡村志愿者管理&#xff0c;文娱活动管理&#xff0c;活动报名管理&#xff0c;医疗保健管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;文娱活…

简单记录一下命名规则

简单记录一下命名规则 1. 记录一下 在编程中&#xff0c;命名规则&#xff08;也称为命名约定&#xff09;是非常重要的&#xff0c;它可以帮助我们编写出更易于理解和维护的代码。一直记不住到底有哪些&#xff0c;稍微记一下&#xff01; 以下是一些常见的命名规则&#xf…

软件推荐 caj2pdf

## 推荐内容 用 zotero 管理文献时&#xff0c;不能处理知网 caj 格时&#xff0c;有大佬做了相应的工作并开源了。 今天推荐这两个 GitHub 项目 https://github.com/caj2pdf/caj2pdfhttps://github.com/ElonH/caj2pdf_gui 一是 python 做的 caj 2 pdf 源码&#xff0c;二是结…

005-OSPF基本配置

OSPF基本配置 OSPF (Open Shortest Path First) 是一种链路状态路由协议&#xff0c;它属于内部网关协议&#xff08;IGP&#xff09;类别&#xff0c;用于在自治系统&#xff08;AS&#xff09;内部路由 IP 数据包。OSPF 通过使用 Dijkstra 算法计算最短路径树来确定到达每个…

Linux之旅: 基础知识点的终极指南

文章目录 1、Linux的目录结构2、ls命令3、管理文件和目录4、linux命令使用细节和技巧5、权限管理基本命令6、搜索命令7、管道符与重定向8、压缩和解压命令9、用户及vim编辑器10、用户和用户组管理一、Linux系统用户账号的基本管理二、Linux系统用户组的管理 1、Linux的目录结构…

【CSS in Depth2精译】1.1.2 行内样式~1.1.3 选择器的优先级

文章目录 1.1.2 行内样式1.1.3 选择器的优先级1.1.3.1 优先级的写法1.1.3.2 关于优先级的思考 1.1.2 行内样式 如果无法通过样式表来源规则解决样式冲突&#xff0c;浏览器则会考察它们是否通过 行内样式 作用于该元素。当使用 HTML 的 style 属性声明样式时&#xff0c;该样式…

Win32编程:第一个窗口程序(Part.1)

Win32系统编程是指在Windows操作系统上使用Win32 API进行软件开发的过程&#xff1b;Win32 API是Windows操作系统提供的应用程序接口&#xff0c;允许程序与操作系统进行交互&#xff0c;实现各种功能。 以下是Win32系统编程的基本概念和步骤&#xff1a; 环境准备 开发工具&…

element-plus的form表单组件之checkbox组件

单个checkbox 绑定的响应式的值类型为bool类型&#xff0c;同一个组的checkbox多选其值对应值的数组&#xff0c;类型根据checkbox的value值而来。 label只用来显示具体的值&#xff0c;根据value属性来设置。 element-plus的checkbox提供多种特性。 如单选&#xff0c;多选…