c语言 编译与链接

news2024/11/28 16:32:25

编译与链接

  • 翻译环境和执行环境
    • 翻译环境
      • 1.1预编译
      • 1.2编译
      • 1.3汇编(ASM)
      • 2.链接
  • 执行环境
    • 最后给大家附上一张关于本节知识内容的图供大家更好理解~ ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/522d488885ba44d99aa504d6b21c88d5.png)

在这里插入图片描述
😀欢迎来到小庄代码世界~
😁 喜欢的小伙伴记得一键三连哦 ૮(˶ᵔ ᵕ ᵔ˶)ა


引言:我们平常写代码是否思考过在我们按下运行时c程序会发生些什么过程呢?
事实上存在翻译和执行环境,这篇文章让博主来分享分享,请放心食用!

翻译环境和执行环境

在ANSIC的任何⼀种实现中,存在两个不同的环境
1.翻译环境 我们知道计算机看懂的是二进制这个环境就是用来将我们的源代码翻译成可执行的二进制指令
2.执行环境 该环境用于实际执行代码
具体如下图

在这里插入图片描述
接下来让博主对翻译环境进行详细讲解´༥`

翻译环境

翻译环境是如何将源代码转换成二进制指令呢?其实翻译环境由编译和链接两大板块组成;而编译又细分为预处理(预编译),编译,汇编三个阶段૮(˶ᵔ ᵕ ᵔ˶)ა

一个项目由多个源文件构成,这些源文件经过编译阶段和编译器(cl.exe)处理生成对应的目标文件,接着对应的目标文件在链接阶段经过连接器(link.exe)生成对应的可执行程序xx.exe文件,这就是大致的翻译环境的流程。

在这里插入图片描述

1.windows系统目标文件的后缀为.obj,而linux下为.o
2.链接库:链接库指的是将库文件编译后打包为一个二进制文件,这些文件在调用的时候会加载到内存中。实际上一个或多个源文件转换为目标文件后,这个文件所引用的外部符号需要通过链接来找缺失的地址,这里我们做个小铺垫~ 我们可以将它理解为我们要借用的大哥的力量,比如标准库函数等。

接下来我们先来了解翻译环境所拆分的三个阶段(以linux环境gcc编译器为例)
在这里插入图片描述
注:对于.i和.s的中间文件他们是临时的用完会删除

1.1预编译

在预处理阶段,源⽂件和头⽂件会被处理成为.i为后缀的⽂件。
在 gcc 环境下想观察⼀下,对 test.c ⽂件预处理后的.i⽂件,命令如下:

gcc -E test.c -o test.i

预编译阶段主要是对预处理指令进行处理,#开头的都是预处理指令他们都是在这个阶段处理的比如#include #define,该阶段特点是替换,将预处理指令替换成它实际指向的内容!

让我们来了解下他的替换规则

1.头文件的包含:处理#include预编译指令,将包含的头⽂件的内容插⼊到该预编译指令的位置。这个过程是递归进⾏的,也就是说被包含的头⽂件也可能包含其他⽂件。
2.#define:它会将所有#define删除并展开它的定义。
3.注释:所有注释都会被替换成空格
4.处理所有的条件编译指令,如: #if、#ifdef、#elif、#else、#endif
5.或保留所有的#pragma的编译器指令,编译器后续会使⽤。

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

最后我们总结一下:预处理主要特点就是将预处理指令指向的实际内容进行替换⌯’▾’⌯

1.2编译

在编译这个阶段主要进行的是符号汇总(先来个铺垫)和将预处理后的⽂件进⾏⼀系列的:词法分析、语法分析、语义分析及优化,⽣成相应的汇编代码⽂件

编译过程的命令如下:

gcc -S test.i -o test.s

🏠 词法分析
词法分析完成的工作主要是识别记号,将源代码程序被输⼊扫描器,扫描器的任务就是简单的进⾏词法分析,把代码中的字符分割成⼀系列的记号(关键字、标识符、字⾯量、特殊字符等)

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

上面的代码经过扫描后得到如下16个记号:
在这里插入图片描述
🏠 语法分析
识别出记号后接下来语法分析器,将对扫描产⽣的记号进⾏语法分析,从⽽产⽣语法树。这些语法树是以表达式为节点的树
在这里插入图片描述
🏠 语义分析
由语义分析器来完成语义分析,即对表达式的语法层⾯分析。编译器所能做的分析是语义的静态分
析。静态语义分析通常包括声明和类型的匹配,类型的转换等。这个阶段会报告错误的语法信息

联系我们之前的知识,我们有链接错误,运行错误,编译错误。编译错误大多是语法错误就是从这而来,由编译阶段来检查

经过3个阶段后所生成就是我们的汇编指令,生成.s后缀文件
在这里插入图片描述
总结:在编译阶段完成工作是将c语言源代码转换成汇编指令,通过词法分析,语法分析,语义分析更好地理解代码。

1.3汇编(ASM)

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

总结:汇编阶段的工作是将汇编代码翻译成二进制指令,生成对应的目标文件

2.链接

链接是一个比较复杂的过程,链接的时候需要把⼀堆⽂件链接在⼀起才⽣成可执⾏程序。链接过程主要包括:地址和空间分配,符号决议和重定位*等这些步骤。链接解决的是⼀个项⽬中多⽂件、多模块之间互相调⽤的问题

你是否一脸雾水( ͡° ʖ̯ ͡°),让博主来给你细细道来

🏠 符号汇总
你是否记得我们在讲编译时有讲到符号汇总这个工作?
所谓符号就是程序中的变量名、函数名,在编译阶段我们会把出现的符号给汇总到一起

🏠 形成符号表
什么是符号表?

符号表是一种供编译器用于保存有关源程序构造的各种信息的数据结构。通俗讲就是存放我们符号属性信息(比如它的存储位置,类型和其他相关信息等)符号表通常需要支持同一符号在一个程序的多重声明。

🏠 符号决议和重定位
我们先上图说话
在这里插入图片描述
这个过程就是符号决议了,概括起来就是只要每个目标文件所引用符号都能在其目标文件中找到唯一定义整个链接过程就是正确的

通过了符号决议后就是进行重定位了修改唯一正确的属性信息

在这里插入图片描述

执行环境

前面的翻译官帮我们翻译完后,计算机就能看懂一系统二进制指令了便可以开始执行程序了

  1. 程序必须载⼊内存中。在有操作系统的环境中:⼀般这个由操作系统完成。在独⽴的环境中,程序
    的载⼊必须由⼿⼯安排,也可能是通过可执⾏代码置⼊只读内存来完成。
  2. 程序的执⾏便开始。接着便调⽤main函数
  3. 开始执⾏程序代码。这个时候程序将使⽤⼀个运⾏时堆栈(stack),存储函数的局部变量和返回
    地址。程序同时也可以使⽤静态(static)内存,存储于静态内存中的变量在程序的整个执⾏过程
    ⼀直保留他们的值.
    4.终⽌程序。正常终⽌main函数;也有可能是意外终⽌。

最后给大家附上一张关于本节知识内容的图供大家更好理解~
在这里插入图片描述

本次知识分享官就体验结束啦〃•ω‹〃,小伙伴们喜欢的话支持小庄给俺点个关注点个收藏来个评论,你们的支持是我更新的强大动力!!

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

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

相关文章

yolov8+deepsort的代码实现

按照官方描述,YOLOv8 是一个 SOTA 模型,它建立在以前 YOLO 版本的成功基础上,并引入了新的功能和改进,以进一步提升性能和灵活性。具体创新包括一个新的骨干网络、一个新的 Ancher-Free 检测头和一个新的损失函数,可以…

Python新手常见问题——列表中删不掉的0

1.测试代码 运行代码 nums1 [1,2,3,0,0,0] print(type(nums1))for i in nums1:if i 0:nums1.remove(i) print(nums1)效果如下 2.疑问: 上面代码,为什么把nums1里面的0移除不干净 3.原因: 在 Python 中,不建议在循环中直接…

蒙特卡洛概率抽样简介

蒙特卡罗方法是一类对概率分布进行随机抽样的技术。 在许多问题领域中,描述或估计概率分布相对简单,但计算所需的数量却很棘手。这可能是由于多种原因造成的,例如domain的随机性质或随机变量的指数级数量增长。 相反,可以通过使…

学校智慧能源消耗管理系统,破解学校节能降耗难题

随着碳达峰、碳中和工作的主要任务,学校作为能源集中地,且能源情况较为复杂的建筑,有效降低能源消耗、减少能源使用成本,已经成为学校一项紧迫的任务。 学校能耗痛点有哪些? 1、规模大 学校是集教学、科研、生活于一…

zabbix客户端配置及自定义监控

部署zabbix客户机 1.服务端和客户端都配置时间同步 yum install -y ntpdate ntpdate -u ntp.aliyun.com 2.服务端和客户端都设置 hosts 解析 cat > /etc/hosts << EOF 172.16.23.16 localhost 172.16.23.17 zbx-server EOF 3.被监控端 //设置 zabbix 的下载源&…

leedcode刷题笔记day1

题目大意&#xff1a; 暴力解法 两个for循环&#xff08;也是我一看到题目想到的方法&#xff09; 枚举在数组中所有的不同的两个下标的组合逐个检查它们所对应的数的和是否等于 target 复杂度分析 时间复杂度:O(n2)&#xff0c;这里 n 为数组的长度 空间复杂度:O(1)&#x…

精彩推荐 | 【深入浅出Docker原理及实战】「原理实战体系」零基础+全方位带你学习探索Docker容器开发实战指南(实战技术总结)

Dockerfile实战总结 前提介绍实战总结方案创建容器时传入环境变量调整宿主机和容器的时间差异解决办法 指定容器的rootfs的大小快速管理容器和镜像快速删除容器的原理--format格式化输出输出所有容器的name输出所有容器名包含test的容器查看退出状态的容器删除所有容器删除/启动…

transbigdata笔记:其他方法

1 出租车相关 1.1 taxigps_to_od 提取出租车OD信息 transbigdata.taxigps_to_od(data, col[VehicleNum, Stime, Lng, Lat, OpenStatus]) 输入出租车GPS数据&#xff0c;提取OD信息 data出租车GPS数据col[VehicleNum, Time, Lng, Lat, OpenStatus]五列 比如GPS数据长这样&am…

docker screen 常用基础命令

1.docker基础命令 1.1开启docker systemctl start docker #开启docker service docker restart #重启docker systemctl stop docker #关闭docker 1.2查看命令 docker images #查看docker镜像docker ps #查看正在运行的镜像或者容器docker ps -a #查看所有容器1.3运…

信驰达科技参与《汽车玻璃集成UWB数字钥匙发展研究白皮书》编制工作

为进一步探索汽车数字钥匙技术路线及开发思路&#xff0c;中国智能网联汽车产业创新联盟&#xff08;CAICV&#xff09;、福耀玻璃工业集团股份有限公司联合发起了《汽车玻璃集成UWB数字钥匙发展研究白皮书》研究工作。 2023年12月20日&#xff0c;由中国智能网联汽车产业创新…

Linux:/proc/kmsg 与 /proc/sys/kernel/printk_xxx

目录 前言一、/proc/kmsg1、简介2、如何修改内核日志缓冲区3、dmesgklogctl 函数&#xff08;来源于 man 手册&#xff09; 4、扩展阅读 二、 /proc/sys/kernel/printk_xxx三、/dev/kmsg 前言 本篇文章将为大家介绍与 Linux 内核日志相关的一些控制文件&#xff0c;共同学习&am…

C语言总结十二:文件操作详细总结

在操作系统中&#xff0c;为了统一对各种硬件的操作&#xff0c;简化接口&#xff0c;不同的硬件设备也都被看成一个文件。对这些文件的操作&#xff0c;等同于对磁盘上普通文件的操作。我们不去探讨硬件设备是如何被映射成文件的&#xff0c;把任意 I/O 设备&#xff0c;转换成…

ResNet论文翻译和精读

1:论文原文 论文原文&#xff1a; ResNet 2&#xff1a;该论文解决了什么问题&#xff1f; 改论文解决了深层的神经网络训练时的梯度消失和梯度爆炸的问题&#xff1b; 3&#xff1a;该论文的创新点&#xff1f; 将快捷连接应用到了网络中构建成了残差网络块&#xff1b;…

【嘉立创EDA-PCB设计指南】3.网络表概念解读+板框绘制

前言&#xff1a;本文对网络表概念解读板框绘制&#xff08;确定PCB板子轮廓&#xff09; 网络表概念解读 在本专栏的上一篇文章【嘉立创EDA-PCB设计指南】2&#xff0c;将设计的原理图转为了PCB&#xff0c;在PCB界面下出现了所有的封装&#xff0c;以及所有的飞线属性&…

代码随想录算法训练营29期|day 22 任务以及具体安排

235. 二叉搜索树的最近公共祖先 class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if(root null) return null;//向左遍历if(root.val > p.val && root.val > q.val){TreeNode left lowestCommonAncestor(roo…

Redis和MySQL如何保持数据一致性

前言 在高并发的场景下&#xff0c;大量的请求直接访问Mysql很容易造成性能问题。所以&#xff0c;我们都会用Redis来做数据的缓存&#xff0c;削减对数据库的请求。但是&#xff0c;Mysql和Redis是两种不同的数据库&#xff0c;如何保证不同数据库之间数据的一致性就非常关键…

基于springboot+vue的在线拍卖系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

redis数据安全(四)复制

关系数据库通常会使用一个主服务器向多个从服务器发送更新&#xff0c;并使用从服务器来处理所有读请求&#xff0c;Redis也采用了同样的方法来实现自己的复制特性&#xff0c;并将其用做扩展性能的一种手段。 一、特点&#xff1a; 1、异步复制&#xff1a;Redis默认使用的是…

Liunx:线程

我们先说一个程序是怎么执行的&#xff1a; 我们编写好一个代码&#xff0c;经过预编译&#xff0c;编译&#xff0c;汇编&#xff0c;连接&#xff0c;形成一个二进制文件被写进磁盘中&#xff0c;通常我们把他叫做可执行程序。 我们可以双击运行&#xff0c;运行需要经过几个…

Modern C++ std::mutex底层原理

前言 我时常有这样的疑问&#xff1a; std::mutex怎么就能保证后面的语句100%安全哪&#xff1f;CPU reordering就不会把这些语句重排到mutex前面执行&#xff1f;而且各个CPU都是有L1、L2缓存的&#xff0c;如果mutex后面要访问的的变量在这些缓存中怎么办&#xff1f; 带着…