当前位置: 首页 > article >正文

C语言:内存中程序是如何运行的

程序是保存在硬盘中的,要载入内存才能运行,CPU 也被设计为只能从内存中读取数据和指令。

对于 CPU 来说,内存仅仅是一个存放指令和数据的地方,并不能在内存中完成计算功能,例如要计算 a = b +c,必须将 a、b、c 都读取到 CPU 内部才能进行加法运算。为了了解具体的运算过程,我们不妨先来看一下CPU 的结构。

CPU 是一个复杂的计算机部件,它内部又包含很多小零件,如下图所示:

运算单元是 CPU 的大脑,负责加减乘除、比较、位移等运算工作,每种运算都有对应的电路支持,速度很快。

寄存器(Register)是 CPU 内部非常小、非常快速的存储部件,它的容量很有限,对于 32 位的 CPU,每个寄存器一般能存储 32 位(4 个字节)的数据,对于 64 位的 CPU,每个寄存器一般能存储 64 位(8 个字节)的数据。为了完成各种复杂的功能,现代 CPU 都内置了几十个甚至上百个的寄存器,嵌入式系统功能单一,寄存器数量较少。

我们经常听说多少位的 CPU,指的就是寄存器的的位数。现在个人电脑使用的 CPU 已经进入了 64 位时代,例如 Intel 的 Core i3、i5、i7 等。

那么,在 CPU 内部为什么又要设置缓存呢?虽然内存的读取速度已经很快了,但是和 CPU 比起来,还是有很大差距的,不是一个数量级的,如果每次都从内存中读取数据,会严重拖慢 CPU 的运行速度,CPU 经常处于等待状态,无事可做。在 CPU 内部设置一个缓存,可以将使用频繁的数据暂时读取到缓存,需要同一地址上的数据时,就不用大老远地再去访问内存,直接从缓存中读取即可。

大家在购买 CPU 时,也会经常关心缓存容量,例如 Intel Core i7 3770K 的三级缓存为 8MB,二级缓存为256KB,一级缓存为 32KB。容量越大,CPU 越强悍。

缓存的容量是有限的,CPU 只能从缓存中读取到部分数据,对于使用不是很频繁的数据,会绕过缓存,直接到内存中读取。所以不是每次都能从缓存中得到数据,这就是缓存的命中率,能够从缓存中读取就命中,否则就没命中。关于缓存的命中率又是一门学问,哪些数据保留在缓存,哪些数据不保留,都有复杂的算法。

CPU指令

要想让 CPU 工作,必须借助特定的指令,例如 add 用于加法运算,sub 用于除法运算,cmp 用于比较两个数的大小,这称为 CPU 的指令集(Instruction Set)。我们的 C 语言代码最终也会编译成一条一条的 CPU 指令。不同型号的 CPU 支持的指令集会有所差异,但绝大部分是相同的。

我们以 C 语言中的加法为例来演示 CPU 指令的使用。假设有下面的 C 语言代码:

int a = 0X14, b = 0XAE, c;
c = a + b;

在 VS2010 Debug 模式下生成的 CPU 指令为:

mov ptr[a], 0X14
mov ptr[b], 0XAE
mov eax, ptr[a]
add eax, ptr[b]
mov ptr[c], eax

mov 和 add 都是 CPU 指令:

1)mov 用来将一个数值移动到一个存储位置。这个数值可以是一个常数,也可以在内存或者寄存器上;这个存储位置可以是寄存器或者内存。

第一条指令中,ptr[a]表示变量 a 的地址,0X14 是一个数值,mov ptr[a], 0X14 表示把数值 0X14 移动到ptr[a] 指向的内存,也就是给变量 a 赋值。第二条指令与此类似。

第三条指令中,eax 是寄存器的名字,该寄存器常用在加法运算中,用来保存某个加数或运算结果,mov eax,ptr[a]表示把变量 a 的值移动到寄存器 eax 中

第五条指令表示把寄存器 eax 的值移动到变量 c 中,此时 exa 中的值为 a、b 相加的和。

2)add 用来将两个数值相加,这两个数值可以在寄存器或者内存中,add 会将相加的结果放在第一个数所在的位置。第四条指令 add eax, ptr[b]表示把 eax 和 ptr[b] 中的数值相加,并把结果放在 eax 中。

总起来讲:第一二条指令给变量 a、b 赋值,第三四条指令完成加法运算,第五条指令将运算结果赋值给变量 c。

实际上,上面的代码是汇编语言,不是 CPU 指令,汇编语言还要经过简单的转换才能成为 CPU 指令;为了更加容易地说明问题,这些语句也没有严格遵守汇编的语法。有兴趣的同学可以自行学习汇编语言,这里不再展开讲解。

本节我们讲解了 CPU 的简单构造以及 CPU 指令,重点是让大家认识寄存器这个小而快速的存储部件,它在程序运行过程中起着至关重要的作用,CPU 就是用它来记录程序的运行状态,然后根据它的值再决定下一步的操作。


http://www.kler.cn/a/501429.html

相关文章:

  • Java 将RTF文档转换为Word、PDF、HTML、图片
  • HTML中meta的用法
  • RuoYi Cloud项目解读【四、项目配置与启动】
  • 科研绘图系列:R语言绘制Y轴截断分组柱状图(y-axis break bar plot)
  • 提升租赁效率的租赁小程序全解析
  • 后端开发 Springboot整合Redis Spring Data Redis 模板
  • SpringBoot开发—— SpringBoot中如何实现 HTTP 请求的线程隔离
  • Golang——Interface类型
  • 关于TCP/IP五层结构的理解
  • Python 中的错误处理与调试技巧
  • 【Elasticsearch】批量操作:优化性能
  • 海外招聘丨卡尔斯塔德大学—互联网隐私和安全副高级讲师
  • Windows 下Mamba2 / Vim / Vmamba 环境安装问题记录及解决方法终极版(无需绕过triton)
  • 【Uniapp-Vue3】表单focus和blue事件的用法
  • VTK知识学习(33)-交互问题2
  • 基于Springboot的汽车维修预约服务系统设计与实现
  • 掌握NI-VISA与SCPI协议:用C#实现高效仪器控制
  • 原生微信小程序中使用Sass
  • 15.2 hana 修改 tenantDB中SAPHANADB用户的密码
  • 9.4 visualStudio 2022 配置 cuda 和 torch (c++)
  • UnityDemo-TheBrave-制作笔记
  • c++——类和对象(中)
  • 《零基础Go语言算法实战》【题目 2-4】一个函数中的多个值
  • Clojure语言的数据结构
  • 【微服务】面试 7、幂等性
  • 【零基础入门Go语言】struct 和 interface:Go语言是如何实现继承的?