电子说
大家好,有很多同学问能不能发下之前的文章,后续我会找一些之前阅读量不错的发下,本文首发于2021年12月,以下是正文。
假定给你一块非常小的内存,这块内存只有8字节,这里也没有高级语言,没有操作系统,你操作的数据单位是单个字节,你该怎样读写这块内存呢?
注意这里的限定,再读一遍,没有高级语言,没有操作系统,在这样的限制之下, 你必须直面内存读写的本质 。
这个本质是什么呢?
本质是你需要意识到内存就是一个一个装有字节的小盒子,这些小盒子从0到N编好了序号。
这时如果你想计算1+2,那么你必须先把1和2分别放到两个小盒子中,假设我们使用Store指令,把数字1放到第6号小盒子,那么用指令表示就是这样:
store 1 6
load r1 6
store $1 6 load r1 6这样就不会有歧义了。
即地址6代表数字1:
地址6 -> 数字1
a = 1
我们可以看到,从表面上看变量a等价于数值1,但背后还隐藏着一个重要的信息,那就是变量a代表的数字1存储在第6号内存地址上,即变量a或者说符号a背后的含义是:
表示数值1
该数值存储在第6号内存地址
到现在为止第2个信息好像不太重要,先不用管它。
既然有变量a,就会有变量b,如果有这样一个表示:
b = a
可以看到,我们完全copy了一份变量a的数据。
现在有了变量,接下来让我们升级一下,假设变量a不仅仅可以表示占用1个字节的数据,也可以表示占用任意多内存的数据,就像这样:
现在变量a占据5个字节,足足占用了整个内存的一大半空间,此时如果我们依然想要表示b = a会怎样呢?
如果你依然采用copy 的方法会发现我们的内存空间已经不够用了,因为整个内存大小就8字节,采用copy的方法仅这两个变量代表的数据就将占据10字节。
怎么办呢?
不要忘了变量a背后可是有两个含义的,再让我们看一下:
表示数值1
该数值存储在第6号内存地址
重点看一下第2个含义,这个含义告诉我们什么呢?
它告诉我们不管一个变量占据多少内存空间,我们总可以通过它在内存中地址找到该数据,而内存地址仅仅就是一个数字,这个数字和该数据占用空间的大小无关。
啊哈,现在变量的第2个含义终于排上用场了,如果我们想用变量b也去指代变量a,干嘛非要直接copy一份数据呢?直接使用地址就不好了,就像这样:
变量a在内存中地址为3,因此变量b中我们可以仅仅存储3这个数字即可。
现在变量b就开始变得非常有趣了。
首先变量b没什么特殊的,只不过变量b存储的东西我们不可以按照数值来解释,而是必须按照地址来解释。
当一个变量不仅仅可以用来保存数值也可以保存内存地址时,指针诞生了。
有很多资料仅仅说指针就是地址,但小风哥认为这是一种偷懒的解释,仅仅停留在汇编层面来理解,有失偏颇,在高级语言中,指针首先是一个变量,只不过这个变量保存的恰好是地址而已,指针是内存地址的更高一级抽象。
如果仅仅把指针理解为内存地址的话你就必须知道所谓的间接寻址。
这是什么意思呢?
如果使用汇编语言来加载变量a的值该怎么写呢?
load r1 1
load r1 @1
地址1 -> 地址3 -> 数据a
b -> 数据a再来对比一下:
地址1 -> 地址3 -> 数据a # 汇编语言层面 变量b -> 数据a # 高级语言层面
这就是所谓的链表了。
指针这个概念首次出现在 PL/I 语言中,当时是为了增加链表处理能力,大家不要以为链表这种数据结构是非常司空见惯的,这在1964年左右并不是一件容易的事情,关于链表你还可以参考这篇《彻底理解链表》。
值得一提的是,Multics操作系统就是 PL/I 语言实现的,这也是第一个用高级语言实现的操作系统,然而Multics操作系统在商业上并不成功,参与该项目的Ken Thompson, Dennis Ritchie后来决定自己写一个更简单的,Unix以及C语言诞生了,或许是在开发Multic时见识到了PL/I语言中指针的威力,C语言中也有指针的概念。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !