1.3 内存
1.3.1 基本概念
1.内存和外存
内存存放当前正在执行的程序和使用的数据,CPU可以直接存取。它由半导体存储器芯片构成,其存取速度快,但成本高,容量比外存的小,断电后内存中的内容会丢失。某些计算机带有后备电池,在断电后为内存提供电源,因此可在断电后维持内存的内容。
外存可用来长期保存大量的程序和数据,CPU需要通过I/O接口访问外存,例如硬盘或CDROM、DVD等。与内存相比,其成本低,容量大,但存取速度较慢。
2.存储器容量
存储器的容量以字节(byte)为单位。字节可用大写字母B表示,1个字节占用一个存储单元,包含8个二进制位(bit),二进制位可用小写字母b表示。在描述比较大的存储容量时,经常使用KB、MB、GB、TB等单位。它们之间的关系为:
1KB=210B=1024B
1MB=220B=1024KB=1048576B
1GB=230B=1024MB=1073741824B
1TB=240B=1024GB=1099511627776B
1PB=250B=1024TB=1125899906842624B
1EB=260B=1024PB=1152921504606846976B
目前,微机的内存容量可以达到64GB,而1块硬盘容量可以达到几个太字节(TB),磁盘阵列中可以包括上百块硬盘,达到PB级的容量,某些大型数据中心甚至可以达到EB级容量。
注意,有的存储器厂家采用这样的公式:
1KB=103B=1000B
1MB=106B=1000KB=1000000B
1GB=109B=1000MB=1000000000B
这就导致这些产品的实际存储容量达不到厂家标称的数值。例如:“SEAGATE ST336752FSUN36G”硬盘的标称容量为36GB,其容量为36420074496字节,约为36.42GB。它是按照1GB=1000000000B计算的。
36420074496/1000000000=36.420074496
但是,如果按照1GB=1073741824B计算,则有:
36420074496/1073741824=33.91883754730224609375
这款硬盘容量约为33.92GB。
3.内存地址及内容
为了正确区分不同的内存单元,给每个单元分配了唯一的地址,地址从0开始编号,顺序递增1。在机器中,地址用无符号二进制数表示,可简写为十六进制数形式。一个存储单元中存放1个字节信息,称为该单元的内容。CPU在读写这个字节时,首先给出这个字节的内存地址,然后内存将数据写入这个地址对应的存储单元,或者将存储单元中的数据读出送给CPU。这里的地址指的是物理地址(Physical Address),在本书后面的部分还会介绍逻辑地址(Logical Address)。
图1-16所示为存储器中部分存储单元的地址及内容。这里的地址和内容都用十六进制表示。
图1-16 物理存储单元的地址及内容
在一些工具软件中,常用图1-17所示的格式紧凑显示存储器内容。
图1-17 物理存储单元的地址及内容
最左边表示存储器的地址。每一行可显示16个字节的内容,字节间用空格隔开,前后8个字节之间用连字符隔开。在这种格式中,全部使用十六进制数表示。在Intel汇编语言语法中,规定十六进制数以0~9数字开头,以H结尾。因此,若1个十六进制数以A~F(大小写任意)开头,则在前应加0,例如,十六进制数E0应表示为0E0H。但图1-17中的所有十六进制数并未加H,这是因为这些软件显示存储器内容时,默认为十六进制数形式。
从中可知,00001000H单元中的内容为25H,00001001H单元中的内容为90H,00001047H单元中的内容为0FH,00001048H单元中的内容为67H。可以记为:
(00001048H)=67H,或 [00001048H]=67H
4.字节、字、双字
(1)字节
字节是PC机中内存存取信息的基本单位。1个字节包含8个二进制位,这8个二进制位按照自左至右的顺序称为第7、6、…、1、0位,相应位编号为b7、b6、…、b1、b0, b7是最高位,b0是最低位。如图1-18所示,25H占1个字节,它的8个二进制位从高到低依次是0、0、1、0、0、1、0、1,最高位为0,最低位为1。
图1-18 字节和二进制位
在有些资料中,把数字的最高位简写为MSB(Most Significant Bit),最低位简写为LSB (Least Significant Bit)。
16位及16位以上的CPU可以在一次操作过程中处理更多的二进制位。例如:80386/80486/Pentium系列处理器可以进行32位的计算,8086、8088处理器可以进行16位的计算。因此,就需要使用字和双字的概念。
(2)字
1个字包含16个二进制位,即两个字节,分别称为高字节和低字节。其位编号为b15~b0, b15是MSB, b0是LSB。其中,b15~b8位是高字节,b7~b0位是低字节。显然,1个字占用两个存储单元。如图1-19所示,9025H是1个字,它的高字节是90H,低字节是25H。9025H的最高位为1,最低位也为1。
图1-19 字的高字节和低字节
(3)双字
1个双字包含32个二进制位,其位编号为b31~b0, b31是MSB, b0是LSB。也可以说它包含4个字节或者2个字,这2个字分别称为高字和低字。显然,1个双字占用4个存储单元。
如图1-20所示,双字0ED69025H的高字为0ED6H,低字为9025H。
图1-20 双字的高字和低字
(4)四字
1个四字包含64个二进制位,其位编号为b63~b0。1个四字占用8个存储单元。
1.3.2 存储器访问
内存最基本的存取单位是字节,内存的物理地址也是以字节为单位的。在访问字节数据时,直接给出所在的地址号即可。但对于字、双字、四字数据类型,由于它们每个数据都要占用多个单元,从而对应多个地址,在访问时如何指定地址呢?数据的存储顺序又是如何确定的呢?
对于字、双字、四字数据类型,Intel CPU在访问这些数据时,只需给出最低单元的地址号,然后依次存取后续字节即可。Intel CPU采用低字节在前(Little Endian)的存储格式。即低地址中存放低字节数据,高地址中存放高字节数据,这就是有些资料中称为“逆序存放”的含义。本书在没有特别说明的情况下,均采用低字节在前的存储格式。
存储1个字占用两个连续单元,这个字的低字节存放在低地址中,高字节存放在高地址中。在存取这个字时,给出其低字节对应的地址即可。例如,把9025H存储到1000H地址中,则低字节25H存储到1000H单元,高字节90H存储到1001H单元,访问时,地址为1000H,如图1-21所示。
图1-21 Little Endian格式存储字型数据
存储1个双字要占用4个连续地址,其低字存放在低地址中,高字存放在高地址中。而在存储每一个字时,同样采用低字节在前、高字节在后的存储方式。例如,将双字0ED69025H存储到00001000H地址中,要占用从该地址开始的4个连续字节。高字0ED6H存储到00001002H单元中,低字9025H存储到00001000H单元中,这个双字的地址为00001000H,如图1-22所示。
图1-22 Little Endian格式存储双字型数据
“低字节低地址、低字低地址”从表面上看起来是十分自然的,但是和我们的阅读习惯有很大的差距。例如,这是内存中的一部分数据:
00001000:25 90 D6 0E 25 40 FC 00 00 00 00 00 25 60 FC 00
从00001000H中取出1个字,应该是2590H,还是9025H呢?从00001000H中取出1个双字,应该是2590D60EH,还是0ED69025H呢?直观的答案是前者,符合我们的阅读习惯。但是,正确答案是后者,后者才符合Intel CPU“低字节在前、低字在前”的Little Endian的存储格式。
在Intel CPU体系结构中,不要求字的地址一定是偶数地址,双字的地址也不一定是4的倍数。对字型数据而言,若其存储在偶数地址,则称为对准字,否则称为未对准字。对双字型数据,若其存储地址是4的倍数,则称为对准双字,否则称为未对准双字。在读取和写入这些未对准的字和双字时,其效率要比读取和写入对准字和对准双字的低。在编程时,应尽量使用对准字和对准双字。
Intel系列CPU采用的是低字节在前(Little Endian)的存储格式,而PowerPC、SPARC、PARC等CPU则采用高字节在前(Big Endian)的存储格式,TCP/IP网络协议也采用Big Endian的方式传输数据,所以,有些资料也把Big Endian方式称为网络字节序。在Big Endian格式中,不允许出现未对准字和未对准双字,如果CPU存取1个未对准字,即它的地址不是偶数,则CPU会产生一个异常。当两台采用不同字节序的主机通信时,在发送数据前,必须经过字节序转换,使之成为网络字节序后再进行传输。
例1.4 对于以下数据,分别按Little Endian、Big Endian存储格式读出0000100C地址的字节、字、双字数据。
00001000:25 90 D6 0E 25 40 FC 00 00 00 00 00 25 60 FC 00
按Little Endian格式读出的字节、字、双字数据(后缀H表示是十六进制数):
(0000100C)字节=25H
(0000100C)字=6025H
(0000100C)双字=00FC6025H
按Big Endian格式读出的字节、字、双字数据:
(0000100C)字节=25H
(0000100C)字=2560H
(0000100C)双字=2560FC00H
显然,Big Endian存储格式更符合人们的阅读习惯。但是,由于本书采用的编程环境是Intel CPU及其兼容系列,因此,在没有特别说明的情况下,均采用低字节在前(Little Endian)的存储格式。
例1.5 对于以下信息,按Little Endian存储格式读出字节、字、双字数据。
00002000:12 34 45 67 89 0A BC DE F0 00
则对于不同的数据类型,00002001号地址的数据是:
(00002001)字节=34H
(00002001)字=4534H
(00002001)双字=89674534H