这是无量测试之道的第166篇原创
1. 内存的物理机制
这篇文章主要讲的是内存的物理机制的原理是什么?以及我们在开发中定义的变量是怎样存储的。认真看完才会觉得很简单,如果只是粗略的看,那就啥都学不到。
首先让我们来看一下内存的物理机制。内存实际上是一种名为内存IC的电子元件。虽然内存IC包括DRAM、SRAM、ROM等多种形式,但从外部来看,其基本机制都是一样的。内存IC中有电源、地址信号、数据信号、控制信号等用于输入输出的大量引脚(IC的引脚),通过为其指定地址(address),来进行数据的读写。
上图是内存IC(在这里假设它为RAM)的引脚配置示例。虽然这是一个虚拟的内存IC,但它的引脚和实际的内存IC是一样的。
VCC和GND是电源,A0~A9是地址信号的引脚,D0~D7是数据信号的引脚,RD和WR是控制信号的引脚。将电源连接到VCC和GND后,就可以给其他引脚传递比如0或者1这样的信号。大多数情况下, 5V的直流电压表示1,0V表示0。
那么,这个内存IC中能存储多少数据呢?数据信号引脚有D0~D7共八个,表示一次可以输入输出8位(=1字节)的数据。此外,地址信号引脚有A0~A9共十个,表示可以指定0000000000~1111111111
共1024个地址。而地址用来表示数据的存储场所,因此我们可以得出这个内存IC中可以存储1024个1字节的数据。因为1024=1KB,所以该内存IC的容量就是1KB。
现在大家使用的计算机至少有512M的内存。这就相当于512000个(512MB÷1KB=512K)1KB的内存IC 。当然,一台计算机中不太可能放入如此多的内存IC。
通常情况下,计算机使用的内存IC中会有更多的地址信号引脚,这样就能在一个内存IC中存储数十兆字节的数据。因此,只用数个内存IC,就可以达到512MB的容量。
下面让我们继续来看刚才所说的1KB的内存IC。首先,我们假设要往该内存IC中写入1字节的数据。为了实现该目的,可以给VCC接入 5V,给GND接入0V的电源,并使用A0~A9的地址信号来指定数据的存储场所,然后再把数据的值输入给D0~D7的数据信号,并把WR(write=写入的简写)信号设定成1_。执行完这些操作,就可以在内存IC内部写入数据了。
向内存IC中写入和读出数据的方法读出数据时,只需通过A0~A9的地址信号指定数据的存储场所,然后再将RD(read=读出的简写)信号设成1即可。执行完这些操作,指定地址中存储的数据就会被输出到D0~D7的数据信号引脚。另外,像WR和RD这样可以让IC运行的信号称为控制信号。其中,当WR和RD同时为0时,写入和读出的操作都无法进行。
由此可见,内存IC的物理机制实质上是很简单的。总体来讲,内存IC内部有大量可以存储8位数据的地方,通过地址指定这些场所,之后即可进行数据的读写。
2.变量是怎样存储的
下面我们来看一个具体的示例。如下所示的代码清单,这是一个往a、b、c这3个变量中写入数据123的C语言程序。这3个变量表示的是内存的特定区域。通过使用变量,即便不指定物理地址,也可以在程序中对内存进行读写。这是因为,在程序运行时,Windows等操作系统会自动决定变量的物理地址。
代码语言:javascript复制char a = '123'
short b = 123
long c = 123
这3个变量的数据类型分别是,表示1字节长度的char,表示2字节长度的short,以及表示4字节长度的long。因此,虽然同样是数据123,存储时其所占用的内存大小是不一样的。这里,我们假定采用的是将数据低位存储在内存低位地址的低字节序。
仔细思考一下就会发现,根据程序中所指定的变量的数据类型的不同,读写的物理内存大小也会随之发生变化,这其实是非常方便的。大家不妨想一想,假如程序中只能逐个字节地对内存进行读写,那该多么不便啊。在处理超过1个字节的数据时,还必须要编写分割处理程序。此外,在不同的编程语言中,变量可以指定的数据类型的最大长度也不相同。C语言中,8字节(=64位)的double类型是最大的。
3.指针
接下来,让我们一起来看一下指针。指针是C语言的重要特征,但很多人都说它难以理解,甚至还有人因无法理解指针而对C语言的学习产生了很强的挫败感。不过,对已经阅读到现在的各位读者来说,指针应该很容易理解。理解指针的关键点就是要弄清楚数据类型这个概念。
指针也是一种变量,它所表示的不是数据的值,而是存储着数据的内存的地址。通过使用指针,就可以对任意指定地址的数据进行读写。虽然前面所提到的假想内存IC中仅有10位地址信号,但大家在Windows计算机上使用的程序通常都是32位(4字节)的内存地址。这种情况下,指针变量的长度也是32位。
请大家看一下代码清单。这是定义了d、e、f这3个指针变量的C语言程序。和通常的变量定义有所不同,在定义指针时,我们通常会在变量名前加一个星号(*)。我们知道,d、e、f都是用来存储32位(4字节)的地址的变量。然而,为什么这里又用来指定char (1字节)、short(2字节)、long(4字节)这些数据类型呢?大家是不是也感到很奇怪?实际上,这些数据类型表示的是从指针存储的地址中一次能够读写的数据字节数。
代码语言:javascript复制char *d
short *e
long *f
假设d、e、f的值都是100。在这种情况下,使用d时就能够从编号100的地址中读写1个字节的数据,使用e时就是2个字节(100地址和101地址)的数据,使用f时就是4个字节(100地址~103地址)的数据。怎么样?指针是不是很简单呢(如下图所示)