[音樂] 前面介绍了各类数值数据和非数值数据的表示
在cpu处理各类数据之前,数据应该存放在存储空间中
现代通用计算机的存储空间,都是按字节编址 即每个字节占一个地址
而cpu处理的数据可能是一个int型的 short型的,float型的或者double型的等等这些数据
那么这些数据都是由多个字节组成的 在存储空间中占有多个存储单元
那么一个数据的多个字节在存储空间中,是如何排列存放的呢
本讲主要介绍两种不同的排列方式 也就是大端方式和小端方式
从80年代开始,我们知道所以通用计算机都是按字节编址
高级语言当中有各种类型的数据,这些数据
具有不同的长度,一个数据可能会占用多个存储单元 比如说,一个int型的变量x
它的值是等于负10,这个x假定是存放在100开始的单元里
也就是说它的地址是100,假定x是负10的话
它的机器数就应该是这样的4个字节,它要占4个单元
那么,负10的这个机器数,实际上我们可以很好算
负10转换成二进制就是它,这样的话
负号那就是转换成这个1,后面应该是全是0 一直到最后是1010
这个是符号位,其实这个我们前面讲过
用各位取反末位加1来转换成它的补码表示,就是增值转换成
补码的时候因为是个负数,所以我们把数值部分各位取反末位加1
那么,各位取反末位加1的时候我们讲过用一个简便方法,就是从最右边往左边看
找到的第一个1前面各位取反,因此
这个符号当然是1,后面各位取反那都是1
然后这位1取反成0,这位是0取反成1,然后
第一个1后面各位照抄,因此最后得出来的就是这样的一个补码,写成
十六进制,那这就是6,前面的当然 全是F,因为全是1,所以是FF
一直到F,最终它的负10的补码就是这样的一个32位的数
它占了4个单元,这4个单元在存储空间里面存放的时候,我们要考虑
以下几个问题,第一个是说,这个x这个变量,它的地址是100 这个100是它占的4个单元当中,
最大的地址呢还是最小的地址呢? 通常我们给出来的这个地址都是最小的地址
也就是说,这个x存放在4个单元里面,其中最小的单元是
100,因此它存放的这个单元号那就是100,101,102,103
这4个单元存放了4个字节
然后第二个问题是说,这4个字节在里面到底该怎么放?
在100号单元里面放的是FF呢,还是放的最后面的F6呢?
放的是最低有效字节F6,还是放的最高有效字节FF呢?
这也是一个问题,这个问题就是大端和小端的问题
也就是说,这4个字节,我们可以这样放
把FF最高有效字节放在100号单元 最低有效字节F6放在103号单元里
也可以反过来放,把最低有效字节F6放在100号单元
最高有效字节FF放在103号单元 那么这两种方法,就分别对应大端和小端
两种方式,这个就是我们刚才讲的存放的这个问题 我们另外再看一个例子,这个i等于负的65535放在
100号单元,如果我们要去访问这个i的时候,我们必须知道 这4个字节是如何放的,那这个65535,
它对应的二进制应该是2的16次方减去1 2的16次方减去1也就是
10......0后面有16个0减1
减下来的结果应该是1,然后前面全是1
第一位是0,因此这个值就是65535
这个值前面添一个负号,就是负的65535
它所对应的补码应该是 符号用1表示,后面的各位取反末位加1,因为
各位取反末位加1,那也就是说,从右边往左边看的第一个1
后面全是不变,前面都是各位取反,因此我们可以 看到它对应的这个补码表示,那就是1
后面呢,各位取反,点点点,一直到
这一位的这个1变成0,这一位的0就是1
前面实际上添足,因为现在是int型的,它有32位
这个实际上是16位,我们刚才讲的这是16个0
所以后面的这边有16个1,是16位
然后这一位的0变成1,前面也全是0
补足,一直到符号位也是1
这样的话,这边实际上是16位,前面加上16个1
所以前面的16个1就是FFFF
后面的就是000,最后一个是1,转换成16位进制数
这是2进制,转换成16进制数,就是这样的一个补码形式,或者是机器数
我们知道负的65535的机器数,就是这样的一个4个字节
然后这4个字节在存储器存放的时候,我们可以 把01,最低有效字节放在100号单元
这个00,放在101号单元,然后这样放,也可以反过来,把最高有效字节
FF放在100号单元,然后把01这个最低有效字节放在
103号单元,那上面的这种方式,我们称为小端
方式,下面的呢称为大端方式,所以我们可以看出 大端方式是这个数的地址上面放的是
最高有效字节,100上面放的是最高有效字节
FF是最高有效字节,这种放法,我们称为大端 IBM
360/370,MIPS等等这些都是一种大端方式,然后小端方式就是反过来
把这个最低有效字节,01是最低有效字节放在 这个100这个位置,放在这个数的地址上面
然后挨个放下去,最高有效字节那就放在 最大的地址上,这样的方式叫小端方式
像Intel架构的都是这种小端方式 有的机器会两种方式都支持,还要用特定的控制位
来设置到底用哪种方式,一旦确定了以后就不再变 下面我们举一个例子
union这样一种数据类型,它的存放顺序使所有的成员变量
都是从低地址开始存放,用这个特性我们可以测定架构的大端还是小端形式,它的存放
是大端还是小端,再有一个union类型里面定义 了一个int型的成员变量和char型的成员变量
那么这个a和b都是占用同一个地址空间 比如说我们这边对a进行了赋值
这个a赋的是,其机器数是12345678
这样的16进制数,也就是这4个字节是12345678
那么假定a和b所在的这个union的地址是从100开始的
若它的这个存放方式可以是这种存放方式 就是它的最高有效字节存放在这个地址上面
然后是最低有效字节在最大的地址上
也可以这样存放,它的最低有效字节 就是78占用了这个地址
就是这个变量的地址,然后最高有效字节占用的是最大的地址
显然上面是大端,下面是小端 然后我们可以通过这个判断,就是看这个b
b应该是存放在100号单元里面的,我们说都是从低地址开始的
那么我们看这个100号单元里面放的是1a的话,我们说它是大端方式 否则我们就说它是小端方式。
100号单元里面放的是12的时候,就是大端方式 否则就是小端方式。
那么在 IA-32上面打印的结果应该是
这个,所以最终的b这个分量应该是等于78
也就是说b里面应该赋的是78,因为它是小端方式
b应该放在这个地方,a占了四个单元,b 只占一个单元,这一个单元就是100,最小的这个地址100
这b应该等于78,打印出来的结果应该是这样子
那么我们再来举一个例子,假定小端 方式的机器里面有一条指令的地址是1000
然后假定这个指令的汇编形式是这样子的 这汇编指令对应的这一个机器代码是这样的一个01序列
那么它的这个操作码呢是40H,16进制的40
这个指令当中的两个寄存器,AX和BX 分别是1号寄存器和2号寄存器,也就是1和2
16进制的1和2,这边指令当中给出了一个立即数
这个立即数假定占32位,那么也就是占了四个字节
这个四个字节就是最低有效字节45 然后前面的是23,再前面是01,再前面就是00
所以这样的四个字节,四个字节存放在这个指令当中 排列顺序是这样的。
很显然 我们可以看到,1000上面放的是40,1001里面放的是12
1002上面放的是45 一直是这样的,所以它是占用1000号单元,这个1和2
合起来一个字节是1001号单元,这是1002号单元
因为它存放的时间是这样一种形式 这样一种形式实际上就是我们讲的小端方式
是最低有效字节占用的 是最小的地址,占用的是最小的地址
这45是最低有效字节,占用的最小的地址,00是最高有效字节
占用的是最大的地址,如果在大端机器上面 这个机器代码它就应该是这样一种形式,40
12 然后是00 01 23 45这样顺着放
所以在这个里面,1000号单元里面当然还是操作码,1001号里面放了两个寄存器的编号
后面四个单元就是立即数,这个立即数是最低
有效字节占用的是最大地址,和小端方式正好相反 这个是指令的存放。
指令当中的 这种数据,像这个立即数,就说指令当中给出来的操作数本身
这个操作数它也有大小端的问题,跟前面这个讲的是一样的 我们再举一个例子
这个是一个反汇编器生成的在IA-32处理器上的一个机器
级表示的文本,前面的这个呢是地址,这个中间呢是二进制的
代码,就是机器指令,后面的这个就是 汇编指令。
汇编指令和机器指令是一一对应的 那么这条机器指令放在这个单元
当中,这个是一个地址,用16位表示的 那么这条指令占了1 2 3 4
5 6,六个字节 占了六个字节,所以这16进制的89所在的地址就是80483d2
85的地址就是80483d3 a0的地址就是80483d4,2
3 4就是这样子排的 那么这个是个机器指令,这边是汇编指令,刚才讲过了
然后在这个机器指令当中,后面的四个字节实际上是立即数
然后我们根据这个反汇编出来的这个结果,可以 猜出这个立即数的值是多少。
考试的时候应该能够看到 根据这个反汇编出来的结果,能够猜出来这个立即数的值是多少。
因为在 这个指令当中给出来的是个机器数,机器数对应的值我们应该能够猜出来
然后所存放的地址,也就是这个立即数到底存放在 什么地址上,我们还可以根据这个反汇编出来的结果
来判断IA-32是大端还是小端方式 那么很显然,它的地址我们刚才讲过了
这个是80483d2 3d3
3d4 这个是80483d4这个地址,那么它的值是多少呢?
这个立即数的机器数是fffffea0,这个机器数
展开以后它实际上就是11 1,e呢是1110
a是10100000
然后这个实际上是一个补码表示,我们要求它的真值
的时候,前面的这个1实际上就是一个负数,然后数值部分各位取反末尾加1
那么各位取反末尾加1有一个简便的方法,就是从后面往前看
碰到的第一个1后面的各位
照抄,然后前面的各位取反,所以0变成1,然后1变成0
0变成1,前面就全部变成0,一直都是0,所以这个
数最后的值就是等于负的101100000
也就是负的1011 00000。
那么这个二进制数 它真正的十进制数是多少呢?我们可以看出来它是1
2 3 4 5 也就是2的5次方,加上2的6次方
加上2的8次方 这是数值部分,然后是负数
所以这个就是等于实际上就是32 加64就是96,加上
256,2的8次方是256 所以这个等于352,然后前面 是个负数。
因此最后的结果,也就是这个立即数
实际上是一个补码表示的数据,这个补码对应的真正的值是负的352
这个很显然是一个小端方式,我们刚才已经讲过了,它实际上
是反过来的,最高有效字节在最高的地址上面
最低有效字节在最低的地址上面,所以它是一种小端方式
那么在机器里面,有的机器我们前面讲过了,是采用的大端方式,有的是采用小端方式
比如说现在有一个数据,它在大端方式下面是放的 是这样的形式,在第0单元是12,第1单元34这样放的
在小端方式里面,那么第0单元放了78 56 34 12 这样放的。
很显然我们可以猜出来放在第0单元的这个数
应该是什么?放在第0单元的这个数据应该是12345678
因为这个最高有效字节是12,最低有效字节是78
所以应该是12345678是在这个上面放的
那么不同机器之间进行程序移植或者数据通讯的时候
一台机器上的这个数字传输到另外一台机器上的时候 会发生问题。
因为有的是用大端,有的用小端,如果不一致的话 就会发生问题。
所以在数据通讯的时候需要转换
先转换成特定的一种格式,然后再转换到某一台机器它的这种格式
在很多文件格式当中或者处理程序当中,也涉及到字节的顺序问题
比如说采用小端方式的这些文件格式,有GIF 还有Paintbrush的这个程序。
采用大端方式 的有Photoshop,JPEG的这种格式也是用大端方式
这是在这个文件之间交换数据,或者是 在机器之间交换数据的时候都要注意这个字节交换问题
在大端和小端之间要转换,都是大端的时候就不需要转换。
[音乐] [音乐]