【C/C++】程序环境,探索程序的执行过程(习得无上内功《易筋经》的第一步)

news2025/1/13 6:09:05

目录

  • 1.程序的翻译环境和执行环境
  • 2.详解编译+链接
    • 2.1翻译环境
    • 2.2编译本身也分为几个阶段
      • 预编译(预处理)
      • 编译
      • 汇编
        • 详解符号表
        • 形成符号表
    • 2.3.链接
      • 合并段表
      • 符号表的合并和重定位
  • 3.运行环境
  • 总结:

1.程序的翻译环境和执行环境

在ANSIC(标准C,ANSI:美国国家标准总局)的任何一种实现中,存在两个不同的环境。

第一种:翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第二次:执行环境,它用于实现执行代码。
在这里插入图片描述

2.详解编译+链接

2.1翻译环境

在这里插入图片描述
在这里插入图片描述

  • 组成一个程序的每个源文件通过编译过程分别转换成目标文件。
  • 每个目标文件由链接器捆绑在一起,形成一个单一而完整的可执行程序。
  • 链接器同时也会引入标准C函数库(链接库)中任何被该程序所用到的函数,而且它可以搜素程序员个人的程序集,将其需要的函数也链接到程序中。

2.2编译本身也分为几个阶段

我现在使用的是VS2019(IDE)—— 集成开发环境
有很多的功能:
编辑+|编译+链接+调试
编辑器+编译器(cl.ese)+ 链接器(link.exe)+ 调试器
VS已经封装的十分好了,我们无法看到编译的过程,想要刨析这些过程这里在Linux环境下进行演示,下面的演示会在Linux下进行。

在这里插入图片描述

gcc -E test.c -o test.i //预编译完成后就停下来,预处理之后产生的结果都放在test.i文件中
gcc -S test.c //编译完成后就停下来,结果保存在test.s中
gcc -c test.c  //汇编完成后就停下来,结果保存在test.o中。

在这里插入图片描述

代码:
test.c

#include<stdio.h>
extern int Add(int, int);
#define MAX 10

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

	return 0;
}

Add.c

int Add(int a1, int a2)
{
	return a1 + a2;
}

输出结果
在这里插入图片描述
可执行程序
在这里插入图片描述

  • 在项目文件夹的Debug下可以查看

预编译(预处理)

  1. 展开头文件

    为头文件(如:#include<stdio.h>,#include被称为预处理指令)中增加头文件信息,测试后大概增加800多行代码。

  2. 注释删除

    经过预编译后,源文件中的注释会被删除。

  3. #define符号替换

    在代码中所有#define定义的宏就会被替换到文本中原来的位置,而#define行会消失。(#define也被称为预处理指令)

  4. 经过预编译后源文件中的C语言代码不会改变。
  • 总的来说,预编译主要做一些文本相关的操作。

Linux命令

  • 使用指令:gcc -E test.c -o test.i
  • 预处理完成后就会停下,预处理的结果会放在test.i文件中。
    在这里插入图片描述
  • 如图说是,为test.i文件内容,它的头文件变为了800多行代码,删除了注释,#define符号被替换
    验证头文件展开
    在这里插入图片描述
  • 在include文件下,找到stdio.h文件,进行对比
    stdio.h文件内容:
    在这里插入图片描述
    我们可以在下面的图中看到,test.i文件的增加内容来自stdio.h文件。
    在这里插入图片描述

编译

  1. 把C语言代码转换成了汇编代码

    将C语言代码转换为汇编代码需要经过4个步骤

    1. 语法分析
    2. 词法分析
    3. 语义分析
    4. 符号汇总
  • 这里重点讲一下符号汇总
    1. 将源文件转化为可执行程序(可执行程序有自己的格式 —— elf文件的格式,可执行程序内容是二进制的)
    2. 符号汇总是将代码中全局变量、函数名汇总起来
    3. 在test.c文件中汇总的是main、Add、printf符号
    4. 在Add.c文件中汇总的是Add符号
    5. 这些汇总在编译阶段看不出什么,符号汇总主要体现在汇编和链接阶段

Linux命令

  • 使用指令:gcc -S test.c
  • 预处理完成后就停下来,结果保存在test.s中。

进入test.s文件后,我们会发现代码已经被转化为汇编语言

在这里插入图片描述

汇编

  1. 汇编后的文件是我们之前在翻译环境中提到的目标文件,目标文件的格式也是elf的

    • 在Windows环境下的目标文件名是xxx.obj
    • 在Linux环境下的目标文件是xxx.o
  2. 该文件把汇编指令转换成二进制指令

    因为计算机只认识二进制指令

  3. 形成符号表

    对不同源文件已完成汇总的符号分别进行分配地址,形成符号表

Linux命令

  • 使用指令:gcc -c test.c
  • 编译完成之后就停下来,结果保存在test.o文件中。
    在这里插入图片描述

这里我们可以看到,经过汇编后,文件转化为二进制形式

详解符号表

  • 在Linux环境下,test.o文件为目标文件,它和可执行文件具有相同的格式:elf格式
  • 在test.o文件中我们可以查看查看它对应源文件的符号表,虽然它是二进制形式的,但我们可以通过readelf工具查看。

查看readelf工具Linux展示:

  • 使用指令:man readelf
    在这里插入图片描述
  • 这里我们使用-s选项查看符号表信息
    在这里插入图片描述
    我们可以进行如下操作查看test.o的符号表:
    在这里插入图片描述
  • test.o符号表中有main、Add、printf符号

查看Add.o符号表:
在这里插入图片描述

  • Add.o符号表中有Add符号

形成符号表

  • 我们已经知道,每个.o文件都有它对应的符号表,符号表里有编译过程中记录的符号,还有与符号相关联的地址。

  • 在编译过程中,test.i文件里面通过extern来声明Add函数,让编译器知道有这个符号。

  • 但Add函数是定义在其他文件里面的,我们只知道有这么个函数,而不能确定它在哪,所以它对应的地址是无效的(随机分配的地址
    在这里插入图片描述

  • 而main函数就在test.c文件中,我们可以找到它,所以我们会给它一个有效的地址。

  • printf函数是库函数,我们暂时不考虑。
    在这里插入图片描述

  • 在Add.c文件里实现了Add函数,我们可以找到它的地址,所以在编译过程,Add.i文件会对Add进行符号汇总,Add.o文件会对Add形成符号表。
    在这里插入图片描述

2.3.链接

  1. 合并段表

    生成一份可执行程序(格式也是elf的),将不同.o文件中的相同段的数据合并

  2. 符号表的合并和重定位

    合并:对所有符号进行合并,将相同的符号进行合并
    重定向:使用有意义的地址(在两个源文件中可能出现两个相同的符号,但一个的地址是无意义的)

合并段表

  • 每个可执行程序或test.o这样的目标文件,它们的格式都是elf文件的格式。这样的文件都有各自的段而且每个文件相同段的格式是相同的,合并段表就是把相同的段合并在一起。
    在这里插入图片描述

符号表的合并和重定位

  • 对所有符号进行合并,将相同的符号进行合并。
  • 取相同符号有意义的地址,进行合并。
  • 如果一个符号直邮无意义的符号,那就会报错。
  • 最终形成的符号表可以方便符号在调用时找到它的地址。
    在这里插入图片描述
    演示调用函数没有定义:
    在这里插入图片描述
  • 将Add函数注释后运行
    在这里插入图片描述
    链接错误,我们将Add函数注释后,编译器找不到Add的有效地址了,就会报错。

3.运行环境

程序执行的过程:

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

总结:

以上的内容只是程序环境和预处理的冰山一角,了解这些可以让你更好的去理解一些知识,比如说在武侠小说中,少林《易筋经》是无上的内功心法,学会的人无不纵横武林,学其它东西都快的很。如果想要了解的更多建议大家下来的看看《程序员的自我修养》这本书,是一本有关于链接、装载与库的书,虽然前期读会比较吃力,建议大家伴随着整个学习过程去看,相信会对你的内功有很大的提升。

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

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

相关文章

LeetCode每日一题——1235. 规划兼职工作

LeetCode每日一题系列 题目&#xff1a;1235. 规划兼职工作 难度&#xff1a;困难 文章目录LeetCode每日一题系列题目示例思路题解题目 你打算利用空闲时间来做兼职工作赚些零花钱。 这里有 n 份兼职工作&#xff0c;每份工作预计从 startTime[i] 开始到 endTime[i] 结束&a…

1024程序员节|基于Springboot实现爱心捐赠管理系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 文末获取源码 项目编号&#xff1a;BS-XX-…

Mybatis-plus学习(基于版本3.0.5)

文章目录一.概念1.1 简介1.2 特性二.快速入门三.CRUD扩展3.1 Insert插入3.2 主键生成策略3.3 Update更新3.4 自动填充3.5 乐观锁3.6 查询操作3.7 删除操作3.8 性能分析插件&#xff08;新版本的Mybatis-plus已将此插件移除&#xff09;3.9 条件构造器3.10 代码生成器一.概念 1…

Transformer合集3

太多了 我都累了 这都第4了 这次先是关于他的小样本目标检测 , 用很少的训练示例检测新目标 小样本目标检测 论文地址&#xff1a; https://openaccess.thecvf.com/content/CVPR2022/papers/Han_Few-Shot_Object_Detection_With_Fully_Cross-Transformer_CVPR_2022_paper.…

docker安装influxdb及备份恢复

influxdb安装influxdb1&#xff0c;拉取镜像2&#xff0c;创建目录并进入到目录内3&#xff0c;创建influxdb容器服务4&#xff0c;访问&#xff1a;ip8086备份恢复influxdb数据准备1.1 创建用户&#xff0c;填入组织&#xff0c;桶信息1.2&#xff0c;给桶添加点数据1&#xf…

ansible部署lnmp架构

环境准备&#xff1a; 主机名IP服务系统ansible192.168.160.131ansibleCentOS-8.5nginx192.168.160.132nginxCentOS-8.5mysql192.168.160.137mysqlCentOS-8.5php192.168.160.139phpCentOS-8.5 1、生成私钥&#xff0c;对另外三台主机进行免密登入 [rootansible ~]# ssh-keyge…

【单片机毕业设计】【mcuclub-jj-007】基于单片机的门铃的设计

最近设计了一个项目基于单片机的门铃&#xff0c;与大家分享一下&#xff1a; 一、基本介绍 项目名&#xff1a;门铃 项目编号&#xff1a;mcuclub-jj-007 单片机类型&#xff1a;STC89C52、STM32F103C8T6 具体功能&#xff1a; 1、通过人体热释电检测是否有人&#xff0c;当…

Java --- 创建SpringMVC项目

目录 一、什么是MVC 二、什么是SpringMVC 三、SpringMVC的特点 四、创建SpringMVC项目 4.1、开发环境 4.2、创建maven工程 4.3、配置web.xml文件 4.4、创建请求控制器 4.5、配置springMVC.xml文件 4.5、访问首页面 4.6、访问指定页面 一、什么是MVC MVC是一种软件架…

C++:C++的IO流

while (scanf("%s", buff) ! EOF)如何终止&#xff1f; 答&#xff1a;ctrl z换行 是规定&#xff0c;ctrl c 是发送信号杀死进程&#xff08;一般不建议ctrl c&#xff09;。 int main() {string str;while (cin >> str) // operator>>(cin, str){cou…

K_A01_001 基于单片机驱动WS2812 点灯流水灯 0-9显示

目录 一、资源说明 二、基本参数 三、通信协议说明 WS2812时序: 代码: 四、部分代码说明 1、接线说明 2、主函数 五、相关资料链接 六、数字提取格式 七、视频效果展示与资料获取 八、项目所有材料清单 九、注意事项 十、接线表格 一、资源说明 单片机型号 测试条件 模…

【一起学习数据结构与算法】优先级队列(堆)

目录一、什么是优先级队列&#xff1f;二、堆 (heap&#xff0c;基于二叉树)2.1 什么是堆&#xff1f;2.2 堆的分类2.3 结构与存储三、堆的操作3.1 堆创建3.2 插入元素3.3 弹出元素四、用堆模拟实现优先级队列五、堆的一个重要应用-堆排序六、经典的TOPK问题6.1 排序6.2 堆一、…

如何用两个晚上教女生学会Python

文章目录安装、需求引导和开发模型命令行计算器用温度指导穿衣VS Code 和女孩子的衣柜用遍历来挑选衣物交互课后作业事情的起因是这样的&#xff0c;知乎上有个妹纸加我&#xff0c;说要相亲。尽管我欣喜若狂&#xff0c;但恰巧在外出差&#xff0c;根本走不开。妹纸于是说要不…

自动化和半自动矢量化提取地物矢量轮廓

假期愉快&#xff08;这个假期加班了没&#xff1f;图片&#xff09;&#xff01;今天小助手来分享关于自动化和半自动化的矢量提取&#xff0c;使用的软件都是我们常用的软件。一是使用Global Mapper对遥感影像或矢量底图进行自动提取&#xff0c;二是基于天地图矢量底图使用A…

阶段性总结 | C语言

… &#x1f333;&#x1f332;&#x1f331;本文已收录至&#xff1a;技术之外的往事 更多知识尽在此专栏中&#xff01; &#x1f389;&#x1f389;&#x1f389;欢迎点赞、收藏、关注 &#x1f389;&#x1f389;&#x1f389;回顾过去 各位CSND的小伙伴们大家好&#xf…

C · 进阶 | 慎看!深剖文件操作,怕你停不下

啊我摔倒了..有没有人扶我起来学习.... 目录前言一、 什么是文件1.1 程序文件1.2 数据文件1.3 文件名二、文件的打开和关闭2.1 文件指针2.2 文件的打开和关闭三、文件的顺序读写3.0 有必要解释一下*3.1 fputc3.2 fgetc3.3 fprintf3.4 fscanf3.4.1来个小总结&#xff08;这里忽略…

双非本23秋招之路-从考研跑路到某安全大厂(无实习、项目)

文章目录双非本23秋招之路-从考研跑路到某安全大厂&#xff08;无实习、项目&#xff09;一、自我介绍二、简历准备三、刷题四、八股文五、项目方面六、关于实习七、面试方面八、秋招路程九、简历投递十、面经分享双非本23秋招之路-从考研跑路到某安全大厂&#xff08;无实习、…

springboot+jsp新闻发布投稿系统

本文采用JSP技术构建的一个管理系统&#xff0c;实现了一个新闻发布系统。新闻发布系统的主要实现功能包括&#xff1a;管理员&#xff1a;首页、个人中心、用户管理 、新闻分类管理 、新闻信息管理、新闻投稿管理、论坛管理、我的收藏管理、投诉建议管理、系统管理。前台首页&…

Python编程 print输出函数

作者简介&#xff1a;一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.输入与输出 1.print&#xff08;&#xff09;输出函数 2.sep 3.en…

【MySQL数据库和JDBC编程】第三章-第一节:MySQL的增删查改基础篇

文章目录一&#xff1a;INSET新增二&#xff1a;SELECT查询&#xff08;1&#xff09;全列查询&#xff08;2&#xff09;指定列查询&#xff08;3&#xff09;查询字段为表达式&#xff08;4&#xff09;起别名&#xff08;5&#xff09;去重&#xff08;DISTINCT&#xff09;…

微信小程序request:fail报错(包括不执行fail回调问题)

微信小程序request:fail报错&#xff08;包括不执行fail回调的问题&#xff09;1. 不执行fail回调的问题2. request:fail报错原因2.1 小程序未配置域名导致的错误2.2 微信小程序使用的服务器环境不支持TLS1.22.3 使用的SSL证书不信任2.4 SSL证书证书链缺乏2.5 域名未备案&#…