你们在吃鸡蛋时,是从鸡蛋的大端敲开还是从小端敲开呢?
这不是开玩笑,这是一个很严肃的问题。

《格列佛游记》中的大小端之争
在《格列佛游记》(Gulliver’s Travels)中,记录着在小人国(Lilliput)里存在着这样一个争端:鸡蛋应该从大端敲开还是从小端敲开?
大端派主张应该从大端敲开鸡蛋,而小端派则认为应该从小端敲开。这一争论甚至引发了严重的宗教战争,导致了大量的冲突和伤亡。
小人国的大小端之争虽然已经结束,但是计算机科学中大小端之争却远没结束。
什么是大端(Big-Endian)和小端(Little-Endian)?
大端Big-Endian和小端Little-Endian是计算机存储多字节数据时的两种不同的字节存储序列。
在大端模式中高位存储在内存的低地址,低位存储在内存的高地址。
假设我们有一个 4 字节的整数 0x12345678,那么它在内存在存储的顺序就是这样的:
地址 内容 0x00 0x12 0x01 0x34 0x02 0x56 0x03 0x78
嗯,你一定发现了,这非常符合我们的阅读习惯,是吧。
由于在网络传输中都使用大端字节顺序,因此大端模式也被称为网络字节序。
小端模式的存储方式
我们再来看看小端模式中它是如何存储。
在小端模式中,低字节存储在低地址,高字节存储在高地址。
那么,同样是刚才4 字节的整数 0x12345678,它将会是这样存储:
地址 内容 0x00 0x78 0x01 0x56 0x02 0x34 0x03 0x12
是的,小端模式的存储和我们看到的刚好相反。
为什么 x86 采用小端模式?
x86 系列处理器采用小端字节序,被广泛普及,现在小端模式已成为 PC 世界的主流。
可是,为什么会这样?
早在60年代,IBM 360 系列计算机是非常有影响力的商用计算机系统,这些系统采用大端字节序。
由于当时 IBM 的市场份额巨大,其设计理念被其他许多计算机系统借鉴,而且大端模式符合人类书写和阅读数字的习惯。例如,我们写“1234”,最高位的1在前,最低位的4在后。因此早期的系统中都采用大端模式。
小端模式的优势
但是工程师也发现大端模式在处理数据时存在诸多问题。
例如整型数字0x12345678,在采用大端存储的情况,如果我只关心最低位字节,这时候仍然要加载4个字节的值。
但如果采用小端存储,因为最低位存储在低地址上,那么直接读取第一个字节的值就可以了。
另外,小端的存储顺序还简化了硬件中算术运算的实现。采用小端模式,可以方便的从内存的低位到高位进位。而且,如果我需要在后边继续扩展位数,也刚好符合内存的增长顺序。
再者以小端存储的情况下,可以通过直接读取前几个字节来获得较短数据类型的值。例如有一个int值被存储在内存中,你可以直接取前两个字节作为 short,或者一个字节作为 char。
此外小端模式还能减少地址计算的复杂性,也能使处理器可以高效地访问未对齐的数据,从而提高了存储效率和性能。
大端模式为何仍用于网络传输?
咦,那既然小端这么好,那为什么大端模式又被用作网络传输时的字节顺序保留了下来呢?
这是因为在网络传输过程中,并不需要进行计算,并且大端字节顺序天然符合人类书写和阅读习惯,这对于查找和调试网络问题大大有利。
因此大端作为网络字节顺序就一直被延用。
网络编程中的字节序转换
在网络编程中,主机和网络传输数据时需要调用 htonl(host to network long)将主机字节转换为网络字节顺序,或者调用 ntohl(network to host long)函数将网络字节转换成主机字节顺序。
结语
最后,回到视频开头,我是喜欢从大端敲开鸡蛋的。
啪


