美文网首页
从计算机电路来理解指针

从计算机电路来理解指针

作者: 红橙Darren | 来源:发表于2024-05-29 22:32 被阅读0次

我学习 C++ 遇到的第一个难以理解的点就是指针,一级指针多级指针搞得晕头转向,为了理解指针,早些年看了很多文章也看过许多视频。当时我都是这么类比的:变量就是我的名字,指针就是我的住址,引用就是我的别名,二级指针是住址的住址,三级指针那就是住址的住址的住址,再往后以此往下类推。

1. 类比法理解

int main() {
    // 定义变量
    int number = 1;
    // 获取指针
    int* p_number = &number;
    // 通过指针操作变量赋值
    *p_number = 2;
    // cout << "number = " << number << endl;
    return 0;
}

以上是一个最简单的代码,number 就是变量的名字,p_number 就是通过变量拿到了住址,*p_number 通过住址找到变量,可以间接的操作变量赋值 。这样理解几乎能解决所有开发中遇到的问题,除非特别复杂奇怪的场景。那后面 new 对象出来的指针呢?其实本质上也都是一样的。

2. 从计算机电路来理解指针

所谓类比,只是方便大家记忆,其实就是说完全不是这么一回事。在计算机看来,变量、指针、住址、别名等等这些,都是不存在的,唯一存在的就是内存高低电压(地址)。接下来,我们试着从计算机电路的角度来理解指针。

汇编结果.png

这图是我们上面的代码编译出来的结果,红色标记的是 cpu 最终要执行的机器码指令,这里是以 16 进制来呈现的,最终编译出来是 101101...... 这样。蓝色标记(希望我没色盲)的是汇编指令,这个是编译的中间产物代码,为了方便我们理解所以我把汇编指令也放出来了。汇编和机器码指令这些不在本文详细解释,不是我们本文的重点,后面我会陆续写一些文章。写文章实在是太耗时间了,一篇文章几乎花掉我一周的业余时间,但视频我可能 10 分钟就能讲清楚。这里我简单用文字解释,大家感兴趣可以去这个网站实践代码:compiler explorer

int number = 1; 
// 对应如下
mov    DWORD PTR [rbp-0xc],0x1

int* p_number = &number;
// 对应如下
lea    rax,[rbp-0xc]
mov    QWORD PTR [rbp-0x8],rax

*p_number = 2;
// 对应如下
mov    rax,QWORD PTR [rbp-0x8]
mov    DWORD PTR [rax],0x2
  • mov DWORD PTR [rbp-0xc],0x1:cpu 读到这条指令将向内存地址 [rbp-0xc] 写入 0x1
  • lea rax,[rbp-0xc]:cpu 读到这条指令将 [rbp-0xc] 的地址值赋值给 rax 寄存器
  • mov QWORD PTR [rbp-0x8],rax:cpu 读到这条指令将 rax 寄存器的值写入 [rbp-0x8] 内存地址
  • mov rax,QWORD PTR [rbp-0x8]:cpu 读到这条指令将 [rbp-0x8] 的值赋值给寄存器 rax
  • mov DWORD PTR [rax],0x2:cpu 读到这条指令将向 rax 内存地址上存的值当作目标地址,写入 0x2,注意这里的 rax 用 [ ] 围起来了

2.1 cup 操作内存地址

cpu 操作内存简图.png
  • cpu 通过地址总线可以选择操作内存条上的某个位置,早期 cpu 只有 20 根地址总线内存只有 1M,现在一般都有 32 根地址线那么就可以达到 4GB。这个就是我们本文所说的内存地址
  • cpu 通过读写操作线可以选择是读入数据还是写入数据
  • cpu 通过数据总线把数据写入内存条,也可以从内存中把数据读入寄存器,32 根线代表我们一次能读取 32 位数据,64 根代表我们一次能读取 64 位数据,也就是我们常说的 32 位计算机与 64 位计算机

现在我们可以来尝试着翻译一下 cup 是如何操作内存地址的了,注意此处省略 cpu 读取指令的操作等等细节,对应代码如下:

int* p_number = &number;

翻译成汇编代码如下:

lea    rax,[rbp-0xc]
mov    QWORD PTR [rbp-0x8],rax

翻译成 cpu 机器指令如下:

01001000100011010100100111110100
01001000100010010100100111111000

假设我们现在 rbp 寄存器的值存的是 0x0f0f0f0d(32位计算机)第一条指令不需要操作内存,把寄存器 rbp 的值减掉 12 存到 rax 寄存器上,执行完第一条指令后,寄存器 rax = rbp - 12 = 0x0f0f0f01。第二条指令需要操作内存,把 rax(0x0f0f0f01) 的值写入到 0x0f0f0f0f5 的内存地址上。将上图的读写操作线设置为写,往读写操作线上传输高低电压来控制读写。往地址总线上传输高低电压来选择地址,32 根地址总线上传输高低电压为 00001111000011110000111100001001(0x0f0f0f0f5)往 32 根数据线上传输高低电压为 00001111000011110000111100000001(0x0f0f0f01)执行完当前指令后,以此类推再去读取下一条指令,继续执行代码。

2.2 cup 内部构造

cpu 芯片的内部构造.png
  • 寄存器:像上面的 rax、rbp 代表的都是 cpu 内部的寄存器,这些电路用来临时存放数据,有记忆功能
  • 计数器:从哪里开始取指令,取完第一条指令执行完就要去取下一条指令,有计数功能
  • 计算器:有些指令需要做加减乘除,有计算功能
  • 控制器:读取指令译码,操作执行指令,控制内存、IO 等,有控制功能

无论多复杂的 CPU 内部都是由电子元器件(主要是晶体管)组成的数字电路,寄存器电路最简单,控制器电路最复杂。这些不在本文的范围内,我有打算后面录制一些科普视频,从电子元器件 -> 数字电路(门电路) -> CPU 内部的详细电路。关于 CPU 芯片卡脖子的制造工艺和历史,我推荐我们 WXG 的微信读书 App 里面的《芯片战争》

3. 最后杂谈

高级语言 -> 汇编语言 -> cpu工作原理 -> 数字电路,再加上数据结构算法、编译原理、操作系统和虚拟机。这个是我的一个学习路径,仅供大家参考。知识浩瀚无限,人的精力和时间却有限,仅仅是一个 linux 操作系统就有上千万行代码,所以我也是一无所知。原则上我们需要尽可能熟悉我们工作的下一层原理,比如以前我做 Android 的时候会花尽可能多的精力去阅读 Framework 的源码,所以之前对于 Android 的分享到 Framework 就打止了。我现在做 iOS 和 C++ 需要了解的就更多了一些。

现代计算机很复杂,我上面画的图非常简单,比如 CPU 内部现在一般都是多核、指令执行有指令流水线、cpu 内部还有多级的快速缓存。我们移动端开发的应用都是运行在操作系统上的,对于我们应用层来说都是虚拟地址,操作系统加上硬件一起配合才会转成真实的物理地址。早期的计算机并没有这么复杂,更有利于大家学习,所以推荐大家先去了解本质,从简单上手再到复杂。

有些语言看似很复杂,但只要是跑在计算机上,那么本质都是一样的。汇编、c/c++、OC、swift 等等只是语法可能有点不一样,但是最终本质大家都是一样的。有些语言依赖虚拟机比如 Java 语言,但 Java/Android 虚拟机是 C/C++ 参杂汇编写的。有些语言依赖解释器比如 python,解释器也 是 C/C++ 参杂汇编写的。学习一门语言的语法其实不用花太多时间,我记得之前从 Android 转到 iOS 开发也就用了一周的时间,关键还是我们对于底层原理的熟悉。

相关文章

  • 《编码》- 读书笔记

    简介: 这本书从最基础的编码、电路、组合学来展开计算机的发展史,各内容之间的连接非常自然,只需有高中基础就可以理解...

  • 【计算机是怎样跑起来的】

    开头的部分讲到了集成电路,I/O、内存、CPU如何配合,对于理解计算机如何输入数据有些形象的画面帮助。 1.计算机...

  • 计算机基础知识-计算机组成与原理之概述篇

    计算机发展简史 阶段:电子管计算机 > 晶体管计算机 > 集成电路计算机(操作系统出现)> 超大规模集成电路计算机...

  • 数字信号的电气特性

    数字信号可以理解为数字电路的信息流,用电路系统里电压的高低来表示二进制1,或者是0。 数字电路其实跟模拟电路在电路...

  • C语言 指针

    # 指针和数组 计算机的硬件指令很大程度上要依赖于地址,所以指针是你能够类似于计算机底层的表达方式来表达自己...

  • 不同编程语言的初心和适用对象

    C 语言 学习内容:指针,内存,数据类型语言本质:理解计算机系统结构解决问题:性能适用对象:计算机类专业 Java...

  • 计算机最基础的部分:存储逻辑电路

    今天我们来实现一个最简单内存。 由于在计算机中除了逻辑电路之外没有别的东西,我们要存储也需要用逻辑电路来实现,接下...

  • 2.7-C语言入门-指针

    1.指针的含义-变量的地址 a.指针:C语言中用“指针”来表示内存地址(即:指针指向了内存地址),即“指针”可理解...

  • 【C】指针

    指针是一个存储计算机内存地址的变量。 从指针指向的内存读取数据称为指针的取值。 指针可以指向某些具体类型的变量地址...

  • 计算机网络简答题

    计算机网络简答题 试从多个方面比较电路交换,报文交换,分组交换 电路交换:通信时 三个阶段 :建立连接,通信,释放...

网友评论

      本文标题:从计算机电路来理解指针

      本文链接:https://www.haomeiwen.com/subject/bwixqjtx.html