(C语言)编译和链接

前言=͟͟͞͞💌:对于现在的各种编译器而言许多都是好多个功能的集成,那么我们的代码到底是如何去实现的呢?难道我们的计算机可以直接读懂我们所写的代码,并运行吗?对于很多细心的小伙伴们可能会想这样的问题。这篇文章带大家来了解一下编译和链接。

目录

⚽️一.翻译环境 

1.预处理(预编译) 

2.编译

(1)词法分析

 (2)语法分析

(3)语义分析 

3.汇编

4.链接

🏀二.运行环境 

🚦三.结言


在ANSI C的任何⼀种实现中,存在两个不同的环境。
第1种是翻译环境,在这个环境中源代码被转换为可执⾏的机器指令。
第2种是执⾏环境,它⽤于实际执⾏代码。

下面来详细的给大家介绍一下下面这两种环境。

⚽️一.翻译环境 

那翻译环境是怎么将源代码转换为可执⾏的机器指令的呢?这⾥我们就得展开开讲解⼀下翻译环境所 做的事情。
其实翻译环境是由编译和链接两个⼤的过程组成的,⽽编译⼜可以分解成:预处理(有些书也叫预编 译)、编译、汇编三个过程。

 如果再把编译器展开成3个过程,那就变成了下⾯的过程:

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.编译

编译过程就是将预处理后的⽂件进⾏⼀系列的:词法分析、语法分析、语义分析及优化,⽣成相应的 、汇编代码⽂件。
编译过程的命令如下:
gcc -S test.i -o test.s
对下⾯代码进⾏编译的时候,会怎么做呢?假设有下⾯的代码
array [index] = (index+ 4 )*( 2 + 6 );

(1)词法分析

将源代码程序被输⼊扫描器,扫描器的任务就是简单的进⾏词法分析,把代码中的字符分割成⼀系列 的记号(关键字、标识符、字⾯量、特殊字符等)。
上⾯程序进⾏词法分析后得到了16个记号:

 (2)语法分析

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

(3)语义分析 

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

3.汇编

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

4.链接

链接是⼀个复杂的过程,链接的时候需要把⼀堆⽂件链接在⼀起才⽣成可执⾏程序。
链接过程主要包括:地址和空间分配,符号决议和重定位等这些步骤。
链接解决的是⼀个项⽬中多⽂件、多模块之间互相调⽤的问题。
我们大部分的错误都是在链接中被查找出来如(使用了未定义的变量,使用了未初始化的变量等)。
我们已经知道,每个源⽂件都是单独经过编译器处理⽣成对应的⽬标⽂件。
test.c 经过编译器处理⽣成 test.o add.c 经过编译器处理⽣成 add.o 我们在 test.c 的⽂件中使⽤了 add.c ⽂件中的 Add 函数和 g_val 变量。我们在 test.c ⽂件中每⼀次使⽤ Add 函数和 g_val 的时候必须确切的知道 Add g_val 的地 址,但是由于每个⽂件是单独编译的,在编译器编译 test.c 的时候并不知道 Add 函数和 g_val 变量的地址,所以暂时把调⽤ Add 的指令的⽬标地址和 g_val 的地址搁置。等待最后链接的时候由 链接器根据引⽤的符号 Add 在其他模块中查找 Add 函数的地址,然后将 test.c 中所有引⽤到Add 的指令重新修正,让他们的⽬标地址为真正的 Add 函数的地址,对于全局变量 g_val 也是类似的⽅法来修正地址。这个地址修正的过程也被叫做:重定位

🏀二.运行环境 

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

🚦三.结言

我们今天的内容就到此为止了感谢大家的观看!

如果喜欢的兄弟们可以点赞关注一键三连!!!(看到一定会回的)

谢谢大家了!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Arduino开发实例-INA219 电流传感器驱动

INA219 电流传感器驱动 文章目录 INA219 电流传感器驱动1、INA219 电流传感器介绍2、硬件准备及接线3、代码实现1、INA219 电流传感器介绍 INA219 模块用于同时测量电流和电压。 该模块使用 I2C 通信传输电压和电流数据。 其他特性: 测量精度:1%最大测量电压:26V最大测量电…

解决小程序字体在最左上角问题

问题如下 原因: 出现这种现象的原因是项目默认开启了Skyline渲染模式,因为Skyline渲染模式不支持原生导航栏,所以在json文件中设置的导航栏失效,文字就会向上移动,如果想要使用原生的导航栏,可以将app.jso…

C#,入门教程(20)——列表(List)的基础知识

上一篇: C#,入门教程(19)——循环语句(for,while,foreach)的基础知识https://blog.csdn.net/beijinghorn/article/details/124060844 List顾名思义就是数据列表,区别于数据数组(arr…

centos7安装Redis7.2.4

文章目录 下载Redis解压Redis安装gcc依赖(Redis是C语言编写的,编译需要)编译安装src目录下二进制文件安装到/usr/local/bin修改redis.conf文件启动redis服务外部连接测试 参考: 在centos中安装redis-5.0.7 Memory overcommit must…

基于JavaWeb+SSM+Vue停车场微信小程序系统的设计和实现

基于JavaWebSSMVue停车场微信小程序系统的设计和实现 滑到文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 滑到文末获取源码 Lun文目录 目录 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相关…

Linux命令手册

简介 Multics(大而全)项目失败,吸取教训启动Unix(小而精),Linus Benedict Torvalds受Unix启发开发初始版本Linux内核,Git也由其开发,目的是为了更好的管理Linux内核开发。Unix是商业…

有线桥接|Wifi隔了一堵墙就没信号?房间的网线口利用起来,让房间死角也有网!

前言 本篇文章是路由器有线桥接主路由,起到AP(热点)的效果 上次发布的无线桥接,使用的前提是需要把旧路由放置在主路由的信号范围内,这极大限制了桥接路由器的放置位置。 如果隔了一堵墙基本上就无法连接Wifi&#x…

供应链安全项目in-toto开源框架详解

引言:in-toto 是一个开源框架,能够以密码学的方式验证构件生产路径上的每个组件和步骤。它可与主流的构建工具、部署工具进行集成。in-toto已经被CNCF技术监督委员会 (Technical Oversight Committee,TOC)接纳为CNCF孵化项目。 1. 背景 由于…

微信小程序之WXML 模板语法之数据绑定、事件绑定、wx:if和列表渲染

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…

一键搭建你的知识库

效果 说明 由于安装包安装需要glibc>2.7 我就不尝试了 因为glib升级是一个繁琐的过程 没有升级的意义 只是为了体验知识库 没必要浪费时间 1.1docker compose部署trilium 1.1.创建目录 mkdir -p /opt/triliumcd /opt/trilium 1.2.编写docker-comppose.yml文件 vim dock…

使用STM32的GPIO口实现LED闪烁

✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进 代码获取、问题探讨及文章转载可私信。 ☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。 🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!&#x1f447…

JavaWeb-Cookie与Session

一、概念 是否还记得我们在HTTP概念中提到:HTTP的一大特点是无状态,这意味着多次HTTP请求之间是无法共享数据的。而在请求之间共享一些数据又是我们期望达到的效果。(例如登录的记住我功能)于是便有了会话跟踪技术,而…

Qt拖拽组件与键盘事件

1.相关说明 1.设置widget或view的拖拽和放置模式函数setDragDropMode参数说明,NoDragDrop(无拖拽和放置)、DragOnly(只允许拖拽)、DropOnly(只允许放置)、DragDrop(允许拖拽和放置)、InternalMove(只移动不复制) 2.设置widget或view的放置动作函数setDefaultDropAct…

python 实现大语言模型中的概率论:两人轮流出手对决时取胜概率的推导

假设你跟朋友通过打赌投篮来打赌一万块。你们找到一个篮球框,然后约定轮流投篮,谁先投进谁赢。假设你投进的概率是 p,也就是投不进的概率是 1-p,你对手投进的概率是 q,投不进的概率是 1-q,如果由你先投,那么…

反序列化提升刷题(2)

今天的例题&#xff1a; <?phphighlight_file(__FILE__);class ctfshowvip{public $username;public $password;public $code;public function __construct($u,$p){$this->username$u;$this->password$p;}public function __wakeup(){if($this->username! || $thi…

解决 vue 项目开发越久 node_modules包越大的问题

解决 vue 项目开发越久 node_modules包越大的问题 node_modules.cache 文件&#xff08;编译缓存文件 可以删除 &#xff09; compression-webpack-plugin 禁止缓存 const CompressionPlugin require("compression-webpack-plugin");module.exports {plugins: [ne…

面向对象之深度优先和广度优先

面向对象深度优先和广度优先是什么&#xff1f; 二叉树的两种遍历是数据结构的经典考察题目, 广度遍历考察队列结构, 深度遍历考察递归 深度优先 先序遍历(父, 左子, 右子) 0, 1, 3, 7, 8, 4, 9, 2, 5, 6 中序遍历(左子, 父, 右子) 7, 3, 8, 1, 9, 4, 0, 5, 2, 6 后序遍历(左子…

SpringBoot跨域问题解决

前端访问后台接口时&#xff0c;浏览器报错&#xff0c;跨域无法访问。 报错信息如下&#xff1a; Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header is present on the requested resource. 经过一番百度之后&#…

【JVM】运行时数据区

文章目录 运行时数据区程序计数器栈栈帧 堆方法区本地方法栈直接内存变量存储位置 面试题本地方法栈有什么用&#xff1f;没有程序计数器会怎么样&#xff1f;说一说Java的内存分布情况类存放在哪里&#xff1f;局部变量存放在哪里&#xff1f; 运行时数据区 java虚拟机在运行…

acwing讲解篇之93. 递归实现组合型枚举

文章目录 题目描述题解思路题解代码 题目描述 题解思路 本题相当于二叉树的深度优先遍历&#xff0c;树的第i层表示第i个数选或不选&#xff0c;当选择了m次左节点后退出 我们记录当前递归的深度deep 然后用state进行状态压缩&#xff0c;state第i位是1表示选第i个数&#xff…