【C】编译与链接
在本文章里面,我们讲会讲解C语言程序是如何从我们写的代码一步步变成计算机可以执行的二进制指令,并最终执行的。C语言程序运行主要包括两大步骤 -- 编译和链接,接下来我们就来一一讲解。
目录
1 翻译环境和运行环境
2 翻译环境
1) 预处理(预编译)
2) 编译
(1) 词法分析
(2) 语法分析
(3) 语义分析
3) 汇编
4) 链接
1 翻译环境和运行环境
在ANSI C(标准C)的任何一种实现里面,都会包含两个不同的环境:
1) 翻译环境:会将源代码转变为可执行的二进制的机器指令。
2) 运行环境:用于执行实际的代码。
两个环境之间的关系可以用图片来描述一下:

用语言简单改过一下就是,各种源文件通过翻译环境中的编译和链接两步,会将我们写的C代码转变成机器能够执行的二进制指令,然后生成可执行程序(.exe为后缀的文件),在运行环境中就可以运行了。
所以可执行程序中存放的都是二进制指令,如果直接用记事本打开会看到是一堆乱码:

2 翻译环境
翻译环境主要由编译和链接两步组成,而编译又由预处理(预编译)、编译、汇编三个过程,所以翻译环境也可以说成是由预处理、编译、汇编、链接四小部分组成。
一个C语言的项目一般会由多个源文件共同构成,每一个源文件会先经过编译器(在vs中为cl.exe)生成对应的目标文件(Windows环境下后缀为.obj,Linux环境下后缀为.o),然后在经过链接器(vs中为link.exe)把各个目标文件和链接库(运行时库(支持程序运行的基本函数的集合)和第三方库)一起链接为可执行程序。


1) 预处理(预编译)
在预处理阶段,源文件和头文件会被处理成为后缀为 .i 的文件。
预处理阶段主要会处理一些以 # 开头的预处理指令,具体规则如下:
| 1 | 将所有的 #define 删除,并展开所有的宏定义 |
| 2 | 处理所有的预编译指令,如 #if 、#endif、#ifdef、#elif、#else 等等 |
| 3 | 处理 #include 预编译指令,将包含的头文件的内容插入到预编译指令的位置 |
| 4 | 删除所有注释 |
| 5 | 添加行号和文件名标识,方便后续编译器生成调试信息等 |
| 6 | 保留所有的 #pragma 的编译器指令,编译器后续使用 |
第6条我们曾在结构体内存对齐中曾经使用过,如:
//修改默认对齐数为1
#pragma pack(1)//还原为默认对齐数
#pragma pack()
2) 编译
编译的主要作用将C语言代码转变为汇编代码,会对文件进行一系列的:词法分析,语法分析,语义分析及优化,生成相应的汇编代码文件。
如以下的这个代码:
arr[index] = (index + 5) * (3 * 8);
(1) 词法分析
将原代码程序输入扫描器,然后由扫描器进行词法分析,将代码中的字符分割成一系列的记号(关键词,标识符,特殊字符等)。上述代码会在扫描器中会分割成以下记号:
(2) 语法分析
经过词法分析之后,语法分析器会对产生的记号进行语法分析,产生语法树(以表达式为结点的树):
(3) 语义分析
接下来就是由语义分析器来完成语义分析,即对表达式进行语法层面分析。编译器的分析是语义分析的静态分析,通常包括声明和类型的匹配,类型转换等等。在这个阶段会报告错误的语法信息。
语义标识后的语法树如图所示:
3) 汇编
经过了预处理和编译之后,就到了汇编阶段,在该阶段会用汇编器将汇编代码转变为机器执行的指令,也就是二进制指令,不做指令优化。
经过了以上三个阶段,就生成了目标文件。
4) 链接
链接会将一堆文件链接在一起,生成一个可执行程序。
链接过程主要包括:地址和空间分配,符号决议和重定位等。其实链接解决的是一个项目中多文件、多模块之间的相互调用问题。
比如:
//add.c
int Add(int x, int y)
{return x + y;
}//test.c
#include<stdio.h>//extern声明外部函数
extern int Add(int, int);int main()
{int a = Add(3, 5);printf("%d\n", a);return 0;
}
在add.c源文件中有一个Add函数。而在test.c源文件中,用extern关键字声明了外部函数并在main函数中使用了Add函数。
其实在链接的过程中,每一个源文件中分别会对函数和全局变量来生成一个符号表,这个符号表里面存储了函数和全局变量的地址,对于定义了的函数和全局变量会在符号表中存储真正的地址,而对于文件中没有定义只是声明的函数和全局变量的地址会先在符号表中存储一个无效的地址,然后链接的时候,会将符号表合并,在其他模块里面寻找真正定义过相同函数和全局变量的地址,来修正文件中引用到该函数的地址,若符号表中仍存在无效地址,咋会报链接错误。
比如在以上例子中,假设test.c 生成的符号表为:
| Add函数 | 0x00000000(无效地址) |
| main函数 | 0x1187f3c0 |
| Add函数 | 0x12f2d7c4 |
在链接时,会将两个符号表合并生成一个新的符号表:
| Add函数 | 0x12f2d7c4 |
| main函数 | 0x1187f3c0 |
再比如以下这个例子:
//add.c
int add(int x, int y)
{return x + y;
}//test.c
#include<stdio.h>extern int Add(int x, int y);int main()
{int ret = Add(3, 5);return 0;
}
| Add函数 | 0x00000000(无效地址) |
| main函数 | 0x1187f3c0 |
| add函数 | 0x12f2d7c4 |
| Add函数 | 0x00000000(无效地址) |
| main函数 | 0x1187f3c0 |
| add函数 | 0x12f2d7c4 |
合成的符号表中出现了无效地址,所以运行时会报链接错误:

相关文章:
【C】编译与链接
在本文章里面,我们讲会讲解C语言程序是如何从我们写的代码一步步变成计算机可以执行的二进制指令,并最终执行的。C语言程序运行主要包括两大步骤 -- 编译和链接,接下来我们就来一一讲解。 目录 1 翻译环境和运行环境 2 翻译环境 1&#…...
Github上传项目
写在前面: 本次博客仅仅是个人学习记录,不具备教学作用。内容整理来自网络,太多了,所以就不放来源了。 在github页面的准备: 输入标题。 往下滑,创建 创建后会跳出下面的页面 进入home就可以看到我们刚…...
webrtc之rtc::ArrayView<const uint8_t>
rtc::ArrayView<const uint8_t> 是 WebRTC(或其他基于 rtc 命名空间的库)中常见的一个类型,它通常用于表示一块 只读的内存区域,该内存区域由一系列 uint8_t 类型(无符号 8 位整数)元素组成。 1. rt…...
Zemax 序列模式下的扩束器
扩束器结构原理 扩束器用于增加准直光束(例如激光束)的直径,同时保持其准直。它通常用于激光光学和其他需要修改光束大小或发散度的应用。 在典型的扩束器中,输入光束是准直激光器,或光束进入第一个光学元件。当光束开…...
Flink系统知识讲解之:如何识别反压的源头
Flink系统知识之:如何识别反压的源头 什么是反压 Ufuk Celebi 在一篇古老但仍然准确的文章中对此做了很好的解释。如果您不熟悉这个概念,强烈推荐您阅读这篇文章。如果想更深入、更低层次地了解该主题以及 Flink 网络协议栈的工作原理,这里有…...
RK3568平台(USB篇)禁用USB端口
一.linux中怎样查看usb的端口号 在USB口插入U盘: [ 198.141319][ T106] usb 3-1.3: new SuperSpeed Gen 1 USB device number 5 using xhci-hcd [ 198.161695][ T106] usb 3-1.3: New USB device found, idVendor=0781, idProduct=5591, bcdDevice= 1.00 [ 198.161721]…...
洛谷 P3000 [USACO10DEC] Cow Calisthenics G
思路 题目要求断若干条边后形成的连通块中,最大的直径最小,很明显的二分。关键就在于如何写 c h e c k check check 函数了。 可以用 d f s dfs dfs 来判断要断哪条边。 一、 d [ u ] d[u] d[u] 定义 设 d [ u ] d[u] d[u] 为从 u u u 出发到子树…...
Web渗透测试之XSS跨站脚本攻击 盲打 详解
目录 XSS盲打 什么是盲打: 盲打主要目的 XSS盲打 什么是盲打: 发现某个页面有xss漏洞 但是注入后没看到效果 而是在其它页面进行xss显示的效果 这种就叫盲打. 我注册了一个网站的用户 注册页面存在xss漏洞跳转到首页 看不到注册信息的输出 当管理员打开页面查看什么用户…...
经典编程题:服务器广播
题目描述: 服务器连接方式包括直接相连,间接连接。A 和 B 直接连接,B 和 C 直接连接,则 A 和 C 间接连接。直接连接和间接连接都可以发送广播。 给出一个 N*N 数组,代表 N 个服务器,matrix[i][j]1…...
【网络协议】静态路由详解
网络中的路由器通过以下两种方式之一发现远程网络: 静态配置路由动态路由协议 在本文,我们将学习关于静态路由的各种概念,例如如何配置静态路由、路由表如何进行决策、路由接口等相关知识。 文章目录 引言直连网络静态路由路由表原则原则1原…...
朝天椒USB服务器在银泰证券虚拟化超融合场景的应用案例
在数字化浪潮席卷金融行业的今天,银泰证券作为业内知名的金融机构,始终致力于提升业务运营效率与数据安全性。面对虚拟化超融合场景下各种认证U盾的管理挑战,银泰证券选择了朝天椒USB服务器作为其解决方案,成功实现了U盾在虚拟机中…...
.NET framework、Core和Standard都是什么?
对于这些概念一直没有深入去理解,以至于经过.net这几年的发展进化,概念越来越多,越来越梳理不容易理解了。内心深处存在思想上的懒惰,以为自己专注于Unity开发就好,这些并不属于核心范畴,所以对这些概念总是…...
FairGuard游戏安全2024年度报告
导 读:2024年,国内游戏市场实际销售收入3257.83亿元,同比增长7.53%,游戏用户规模6.74亿人,同比增长0.94%,市场收入与用户规模双双实现突破,迎来了历史新高点。但游戏黑灰产规模也在迅速扩大&…...
JetBrains IDEs和Visual Studio Code的对比
JetBrains IDEs和Visual Studio Code的对比 JetBrains IDEs是捷克JetBrains公司开发的一系列集成开发环境(IDE)。以下是具体介绍:IntelliJ IDEA是JetBrains 公司的一款产品 主要产品 IntelliJ IDEA:一款功能强大且广泛应用的Java集成开发环境,有开源免费的社区版和商业收…...
文件剪切走:深度解析与高效恢复策略
一、文件剪切走现象解读 在计算机的日常使用中,“文件剪切走”这一术语形象地描述了文件在移动过程中意外丢失的现象。当用户尝试将文件从一个位置“剪切”并粘贴到另一个位置时,如果操作不当或系统出现异常,可能会导致文件在源位置消失&…...
Win32汇编学习笔记09.SEH和反调试
Win32汇编学习笔记09.SEH和反调试-C/C基础-断点社区-专业的老牌游戏安全技术交流社区 - BpSend.net SEH - structed exception handler 结构化异常处理 跟筛选一样都是用来处理异常的,但不同的是 筛选器是整个进程最终处理异常的函数,但无法做到比较精细的去处理异常(例如处理…...
[人工智能]CSDN创作助手体验
一、什么是智能体 智能体是一种能够感知环境、学习、推理和行动的实体。它可以是一个计算机程序、机器人或其他类似的系统。智能体的目标是通过与环境的交互来实现特定的任务或目标。 智能体通常由以下几个组件组成: 感知器:感知器是智能体与环境之间的…...
vue3中el-table实现多表头并表格合并行或列
1、el-table中添加事件 :span-method"genderSpanCity" <el-table :span-method"genderSpanCity":data"data.tableData":fit"true" table-layout"fixed" header-align"center" stripestyle"width:100%;he…...
HTML+CSS+JS制作中国传统节日主题网站(内附源码,含5个页面)
一、作品介绍 HTMLCSSJS制作一个中国传统节日主题网站,包含首页、节日介绍页、民俗文化页、节日活动页、联系我们页等5个静态页面。其中每个页面都包含一个导航栏、一个主要区域和一个底部区域。 二、页面结构 1. 顶部横幅区 包含传统中国风格的网站标题中国传统…...
时空笔记:CBEngine(微观交通模拟引擎)
CBEngine 是一个微观交通模拟引擎,可以支持城市规模的道路网络交通模拟。CBEngine 能够快速模拟拥有数千个交叉路口和数十万辆车辆的道路网络交通。 以下内容基本翻译自CBEngine — CBLab 1.0.0 documentation 1 模拟演示 1.0 模拟演示结构 config.cfg 定义了 roa…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
密码学基础——SM4算法
博客主页:christine-rr-CSDN博客 专栏主页:密码学 📌 【今日更新】📌 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 编辑…...
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑 在电子商务领域,转化率与网站性能是决定商业成败的核心指标。今天,我们将深入解析不同类型电商平台的转化率基准,探讨页面加载速度对用户行为的…...
python基础语法Ⅰ
python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器,来进行一些算术…...
