且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

《操作系统真象还原》——0.19 什么是大端字节序、小端字节序

更新时间:2021-08-17 05:33:57

本节书摘来自异步社区《操作系统真象还原》一书中的第0章,第0.19节,作者:郑钢著,更多章节内容可以访问云栖社区“异步社区”公众号查看

0.19 什么是大端字节序、小端字节序

先说一下为什么会产生字节序的问题。

内存是以字节为单位读写的,其最小的读写单位就是字节。故如果在内存中只写入一个字节,一个内存的存储单元便可将其容纳了,只要访问这一内存地址就能够完整取出这1字节。可是1字节要能够表示的范围只有0~255(先只考虑无符号数),超过这个范围的数,只好用多个字节连在一起来表示。因此,在我们的32位程序中,定义的数据类型很多。1字节的数据类型只有char型,像int型要占4字节,double型要占用8字节。正如解决了一个问题又抛出了新的问题一样,解决了数值范围的问题,那带来的新的问题是这么多个字节该以怎样的顺序排放呢。一个超过255的数字必然要占用2个字节以上,这两个字节,在物理内存中,哪个在前?哪个在后?拿0x1234举例,数值中的高位12是放在内存的高地址处,还是低地址处?

于是就产生了这两种相反的排列顺序。

(1)小端字节序是数值的低字节放在内存的低地址处,数值的高字节放在内存的高地址。

(2)大端字节序是数值的低字节放在内存的高地址处,数值的高字节放在内存的低地址。

为了让大家理解得更直观,我在虚拟机bochs中操作一下,咱们看一下真正的0x12345678在内存中是怎样存储的,如图0-9所示。

上面的b 0x7c00是我在内存的0x7c00处插入了一个断点,其实这与要说明的问题无关,怕有同学好奇就稍带说一句,因为0x7c00是BIOS把mbr加载到内存后会跳转过去的地址,所以在此处能停下来。咱们只要关注xp/4 0x200000,这是显示以物理内存0x200000开始处的4个字节,可见其为00、00、00、00,地址是从左到右逐渐升高的,其中每一对00就占用1个字节,它们的值都是0。现在用setpmem命令在该地址处写入0x12345678后,再用xp/4命令查看内存地址0x200000处的内容,可见已经不是4个00了,由内存的低地址到高地址,依次变成了0x78、0x56、0x34、0x12。这说明bochs模拟的x86体系结构虚拟机是小端字节序,即数值上的低字节0x78在物理内存上的低地址,其他数值也依次符合小端字节序。

选择哪种字节序,这是硬件厂商考虑的问题,对于这种二选一的选择,选择了一方的时候,就必然丢了另一方。

看看这两种字节序的优势。

(1)小端:因为低位在低字节,强制转换数据型时不需要再调整字节了。

(2)大端:有符号数,其字节最高位不仅表示数值本身,还起到了符号的作用。符号位固定为第一字节,也就是最高位占据最低地址,符号直接可以取出来,容易判断正负。

简要说明一下小端的优势。因为在做强制数据类型转换时,如果转换是由低精度转向高精度,这数值本身没什么变化,如short 是2字节,将其转换为4字节的int类型,无非是由0x1234变成了0x00001234,数值上是不变的,只是存储形式上变了。如果转换是高精度转向低精度,也就是多个字节的数值要减少一些存储字节,这必然是要丢弃一部分数值。编译器的转换原则是强制转换到低精度类型,丢弃数值的高字节位,只保留数值的低字节,如图0-10所示。

《操作系统真象还原》——0.19 什么是大端字节序、小端字节序

由图0-10上输出可见,0x12345678由4字节的int型强制转向了2字节的short型后,只保留了低字节的0x5678。

对于大端的优势,就硬件而言,就是符号位的判断变得方便了。最高位在最低地址,也就是直接就可以取到了,不用再跨越几个字节,减少了时钟周期。另外,对于人类来说,还是大端看上去顺眼,毕竟咱们存储0x12345678到内存时,它在内存中的存储顺序也是0x12345678,而不是0x78563412,这样看上去才直观。

常见CPU的字节序如下。

(1)大端字节序:IBM、Sun、PowerPC。

(2)小端字节序:x86、DEC。

ARM体系的CPU则大小端字节序通吃,具体用哪类字节序由硬件选择。

字节序不仅是在CPU访问内存中的概念,而且也包括在文件存储和网络传输中。bmp格式的图片就属于小端字节序,而jpeg格式的图片则为大端字节序,这没什么可说的,采用什么序列完全是开发者设计产品时的需要。

网络字节序就是大端字节序,所以在x86架构上的程序在发送网络数据时,要转换字节顺序。

关于字节序就介绍到这里,读者若觉得意犹未尽可以自行查阅。