【C语言编译与链接】--翻译环境和运行环境,预处理,编译,汇编,链接

news2025/7/23 7:03:37

目录

一.翻译环境和运行环境

 二.翻译环境

2.1--预处理(预编译) 

2.2--编译

2.2.1--词法分析 

2.2.2--语法分析 

2.2.3--语义分析 

2.3--汇编

2.4--链接 

三.运行环境 


🔥个人主页:@草莓熊Lotso的个人主页

🎬作者简介:C++研发方向学习者

📖个人专栏:《C语言》

⭐️人生格言:生活是默默的坚持,毅力是永久的享受。


一.翻译环境和运行环境

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

  1. 翻译环境,在这个环境中源代码被转换为可执行的机器指令(二进制指令)。
  2. 执行环境,它用于实际执行代码。


 二.翻译环境

--那么我们翻译环境是怎么把源代码转换为可执行的机器指令的呢?这里我们就得详细的了解一下翻译环境所做的事。

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

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

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

我们再把编译器展开为3个过程看看(以gcc为例),如下图:

2.1--预处理(预编译) 

--在预处理阶段,源文件和头文件会被处理成为.i为后缀的文件。如果我们想要在gcc环境下进行观察对test.c文件预处理后的.i文件,命名如下:

1.   gcc  -E  test.c  -o  test.i

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

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

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

这里先简单的介绍一下,后面会更新预处理详解来更加深入的分享预处理的相关知识。

2.2--编译

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

编译过程的命令如下:

1.  gcc  -S  test.i  -o  test.s

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

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

2.2.1--词法分析 

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

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

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

2.2.2--语法分析 

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

2.2.3--语义分析 

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

2.3--汇编

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

2.4--链接 

  • 链接是⼀个复杂的过程,链接的时候需要把⼀堆文件链接在⼀起才生成可执行程序。
  • 链接过程主要包括:地址和空间分配,符号决议和重定位等这些步骤。
  • 链接解决的是⼀个项目中多文件、多模块之间互相调用的问题。
比如:
在⼀个C的项目中有2个.c文件( test.c add.c ),代码和图示如下:
test.c:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

//声明外部符号的
extern int g_val;
extern int Add(int, int);

int main()
{
	int a = 10;
	int b = 20;
	int c = Add(a, b);
	printf("c = %d\n", c);
	printf("g_val = %d\n", g_val);

	return 0;
}

add.c:

#define _CRT_SECURE_NO_WARNINGS

int g_val = 2025;//全局变量
int Add(int x, int y) //函数
{
	return x + y;
}

运行结果:

编译过程图示解析: 

我们来思考两个问题:

  1. 我们能不能把add.c里的代码全部注释掉?
  2. 我们能不能只吧add.c里的Add改成ADD或者add?

答案是都不可以,无论是上述那种情况,最后都会发生编译错误


三.运行环境 

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

往期回顾:

【通关文件操作(上)】--文件的意义和概念,二进制文件和文本文件,文件的打开和关闭,文件的顺序读写

【通关文件操作(下)】--文件的顺序读写(续),sprintf和sscanf函数,文件的随机读写,文件缓冲区,更新文件

结语:本篇文章就到此结束了,继前面一篇文章后,在此篇文章中给大家分享了编译与链接中的翻译环境和运行环境,预处理,编译,汇编,链接等知识点,后续会继续分享预处理的详解,如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持。

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

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

相关文章

【JavaEE】多线程

8.线程状态 根据 Java 的Thread.state包&#xff0c;线程一共有六种状态&#xff1a; NEWRUNNABLEBLOCKEDWAITINGTIMED_WAITINGTERMINATED 二、每种状态的含义 1. NEW&#xff08;新建&#xff09; 当使用new 关键字创建一个线程对象&#xff0c;但尚未调用其start() 方法时…

【项目】在线OJ(负载均衡式)

目录 一、项目目标 二、开发环境 1.技术栈 2.开发环境 三、项目树 目录结构 功能逻辑 编写思路 四、编码 1.complie_server 服务功能 代码蓝图 开发编译功能 日志功能 ​编辑 测试编译模块 开发运行功能 设置运行限制 jsoncpp 编写CR 如何生成唯一文件名 …

贪心算法应用:在线租赁问题详解

贪心算法应用&#xff1a;在线租赁问题详解 贪心算法是一种在每一步选择中都采取当前状态下最优的选择&#xff0c;从而希望导致结果是全局最优的算法策略。在线租赁问题(Greedy Algorithm for Online Rentals)是一个经典的贪心算法应用场景&#xff0c;下面我将从多个维度全面…

Prj10--8088单板机C语言8259测试(1)

1.原理图 2.Deepseek示例代码 #include <dos.h> #include <conio.h> #include <stdio.h>#define PIC1_CMD 0x400 // 命令端口 (A00) #define PIC1_DATA 0x401 // 数据端口 (A01)volatile int int_count 0; // 中断计数器 void interrupt (*old_isr)(…

3步在小米13手机跑DeepSeek R1

大家好&#xff01;我是羊仔&#xff0c;专注AI工具、智能体、编程。 一、从性能旗舰到AI主机 春节大扫除时&#xff0c;翻出尘封的小米13&#xff0c;这台曾以骁龙8 Gen2著称的性能小钢炮&#xff0c;如今正在执行更科幻的使命——本地运行DeepSeek R1。 想起两年前用它连续肝…

注销微软账户

因为我的微软开发者账户丢失 Office E5 权限&#xff0c;因此需要注销。 若你需要注销微软账号&#xff0c;请点击下方超链接。 点击此处 注销之后仅剩一个正常的账户使用咯&#xff01;&#xff01;

Ubuntu 服务器软件更新,以及常用软件安装 —— 一步一步配置 Ubuntu Server 的 NodeJS 服务器详细实录 3

前言 前面&#xff0c;我们已经 安装好了 Ubuntu 服务器系统&#xff0c;并且 配置好了 ssh 免密登录服务器 &#xff0c;现在&#xff0c;我们要来进一步的设置服务器。 那么&#xff0c;本文&#xff0c;就是进行服务器的系统更新&#xff0c;以及常用软件的安装 调整 Ubu…

飞牛NAS+Docker技术搭建个人博客站:公网远程部署实战指南

文章目录 前言1. Docker下载源设置2. Docker下载WordPress3. Docker部署Mysql数据库4. WordPress 参数设置5. 飞牛云安装Cpolar工具6. 固定Cpolar公网地址7. 修改WordPress配置文件8. 公网域名访问WordPress总结 前言 在数字化浪潮中&#xff0c;传统网站搭建方式正面临前所未…

刷leetcode hot100返航必胜版--链表6/3

链表初始知识 链表种类&#xff1a;单链表&#xff0c;双链表&#xff0c;循环链表 链表初始化 struct ListNode{ int val; ListNode* next; ListNode(int x): val&#xff08;x&#xff09;,next(nullptr) {} }; //初始化 ListNode* head new ListNode(5); 删除节点、添加…

C# 序列化技术全面解析:原理、实现与应用场景

在软件开发中&#xff0c;数据持久化和网络通信是两个至关重要的环节。想象一下&#xff0c;当我们需要将一个复杂的对象保存到文件中&#xff0c;或者通过网络发送到另一台计算机时&#xff0c;如何有效地表示这个对象&#xff1f;这就是序列化技术要解决的问题。序列化&#…

electron定时任务,打印内存占用情况

// 监听更新 function winUpdate(){// 每次执行完后重新设置定时器try {// 获取当前时间并格式化为易读的字符串const now new Date();const timeString now.toLocaleString();console.log(当前时间: ${timeString});// 记录内存使用情况&#xff08;可选&#xff09;const m…

Gitee Wiki:以知识管理赋能 DevSecOps,推动关键领域软件自主演进

关键领域软件研发中的知识管理困境 传统文档管理模式问题显著 关键领域软件研发领域&#xff0c;传统文档管理模式问题显著&#xff1a;文档存储无系统&#xff0c;查找困难&#xff0c;降低效率&#xff1b;更新不及时&#xff0c;与实际脱节&#xff0c;误导开发&#xff1…

学习STC51单片机24(芯片为STC89C52RCRC)

每日一言 把 “我不行” 换成 “我试试”&#xff0c;你会发现一片新的天地。 那关于优化 白盒测试 我们之前不是通过这个接线方式可以看到返回到信息嘛因为安信可的特性就是返回Esp8266的反馈&#xff0c;可以看到代码死在哪里了&#xff0c;导致连接不上&#xff0c;因为我们…

LabVIEW基于 DataSocket从 OPC 服务器读取数据

LabVIEW 中基于 DataSocket 函数从 OPC 服务器读取数据的功能&#xff0c;为工业自动化等场景下的数据交互提供了解决方案。通过特定函数实现 URL 指定、连接建立与管理、数据读取&#xff0c;相比传统 Socket 通信和 RESTful API &#xff0c;在 OPC 服务器数据交互场景有适配…

阿里云无影云桌面深度测评

阿里云无影桌面深度测评&#xff1a;解锁云端工作“新范式”的“未来之钥”&#xff01; 在数字化浪潮席卷全球的2025年&#xff0c;远程办公与混合办公已不再是权宜之计&#xff0c;而是职场不可逆转的新常态。然而&#xff0c;如何确保员工无论身在何处&#xff0c;都能拥有…

深入浅出:Oracle 数据库 SQL 执行计划查看详解(1)——基础概念与查看方式

背景 在当今的软件开发领域&#xff0c;尽管主流开发模式往往倾向于采用单表模式&#xff0c;力图尽可能地减少表之间的连接操作&#xff0c;以期达到提高数据处理效率、简化应用逻辑等目的。然而&#xff0c;对于那些已经上线运行多年的运维老系统而言&#xff0c;它们内部往…

前端​​HTML contenteditable 属性使用指南

​​什么是 contenteditable&#xff1f; HTML5 提供的全局属性&#xff0c;使元素内容可编辑类似于简易富文本编辑器兼容性​​ 支持所有现代浏览器&#xff08;Chrome、Firefox、Safari、Edge&#xff09; 移动端&#xff08;iOS/Android&#xff09;部分键盘行为需测试 &l…

自动化采集脚本与隧道IP防封设计

最近群里讨论问如何编写一个自动化采集脚本&#xff0c;要求使用隧道IP&#xff08;代理IP池&#xff09;来防止IP被封。这样的脚本通常用于爬虫或数据采集任务&#xff0c;其中目标网站可能会因为频繁的请求而封禁IP。对于这些我还是有些经验的。 核心思路&#xff1a; 1、使…

【设计模式-4.7】行为型——备忘录模式

说明&#xff1a;本文介绍行为型设计模式之一的备忘录模式 定义 备忘录模式&#xff08;Memento Pattern&#xff09;又叫作快照模式&#xff08;Snapshot Pattern&#xff09;或令牌模式&#xff08;Token Pattern&#xff09;指在不破坏封装的前提下&#xff0c;捕获一个对…

docker离线镜像下载

背景介绍 在某些网络受限的环境中&#xff0c;直接从Docker Hub或其他在线仓库拉取镜像可能会遇到困难。为了在这种情况下也能顺利使用Docker镜像&#xff0c;我们可以提前下载好所需的镜像&#xff0c;并通过离线方式分发和使用。 当前镜像有&#xff1a;python-3.8-slim.ta…