知识点:谈谈字节顺序和大小端模式

移动端团队 @ 奇舞团(360集团大前端团队)

一、什么是字节序

字节顺序,是指数据在内存中的存放顺序

  • 举例说明什么是字节顺序

使用16进制表示两个数:0x12345678和0x11223344。在内存中有两种方法存储这两个数字,分别为:

从上图看,两种方案虽有不同,但也有共识,即依次存储每一个数字,即先存0x12345678,再存0x11223344。大家的不同在于,对于某一个要表示的值,是把值的低位存到低地址,还是把值的高位存到低地址。

二、字节顺序的分类

字节的排列方式有两种。例如,将一个多字节对象的低位放在较小的地址处,高位放在较大的地址处,则称小端序;反之则称大端序

在几乎所有的机器上,多字节对象都被存储为连续的字节序列。例如在C语言中,一个类型为int的变量x地址为0x100,那么其对应地址表达式&x的值为0x100。且x的四个字节将被存储在电脑内存的0x100, 0x101, 0x102, 0x103位置。

  • 大端、小端模式的区别

    例如假设变量x类型为int,位于地址0x100处,它的值为0x01234567,地址范围为0x100~0x103字节,其内部排列顺序依赖于机器的类型。大端法从首位开始将是:0x100: 0x01, 0x101: 0x23,..。而小端法将是:0x100: 0x67, 0x101: 0x45,..

  • 不同处理器体系

    • x86,MOS Technology 6502,Z80,VAX,PDP-11等处理器为Little endian。
    • Motorola 6800,Motorola 68000,PowerPC 970,System/370,SPARC(除V9外)等处理器为Big endian。
    • ARM, PowerPC (除PowerPC 970外), DEC Alpha, SPARC V9, MIPS, PA-RISC and IA64的字节序是可配置的。

三、网络字节序

对于搞网络通信应用(比如IM、消息推送、实时音视频)开发的程序员来说,自已写通信底层的话是一定会遇到大小端问题,上面所说的大小端字节序都是在说计算机自己,也被称作主机字节序。同型号计算机上写的程序,在相同的系统上面运行是没有问题的。

但计算机网络的出现让大小端问题变的复杂化了,因为每个计算机都有自己的主机字节序。不同计算机之间通过网络通信时:我“说”的你听不懂,你“说”我也听不懂,这可怎么办?这时候就需要约定俗成的协议来解决问题。

TCP/IP协议很好的解决了这个问题,TCP/IP协议规定使用“大端”字节序作为网络字节序。

这样不管计算机采用哪种字节序,发送数据的时候必须将自己的主机字节序转换为网络字节序(即“大端”字节序),对接收到的数据转换为自己的主机字节序。这样一来,也就达到了与CPU、操作系统无关,实现了网络通信的标准化。

  • 主机字节序到网络字节序的转换

    为了程序的兼容,网络通信过程中每次发送和接受数据都要进行转换,这样做的目的是保证代码在任何计算机上执行时都能达到预期的效果。

    通信时的这种常用的操作,Socket API这一层,一般都提供了封装好的转换函数,方便程序员使用。比如从主机字节序到网络字节序的转换函数:htons、htonl(C语言中常用),从网络字节序到主机字节序的转换函数:ntohs、ntohl(C语言中常用)。当然,明白了原理后也可以编写自己的转换函数。

四、大小端(endian)的来源

endian”一词来源于十八世纪爱尔兰作家乔纳森·斯威夫特(Jonathan Swift)的小说《格列佛游记》(Gulliver's Travels)。小说中,小人国为水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开而争论,争论的双方分别被称为“大端派”和“小端派”。以下是1726年关于大小端之争历史的描述:

我下面要告诉你的是,Lilliput和Blefuscu这两大强国在过去36个月里一直在苦战。战争开始是由于以下的原因:我们大家都认为,吃鸡蛋前,原始的方法是打破鸡蛋较大的一端,可是当今皇帝的祖父小时候吃鸡蛋,一次按古法打鸡蛋时碰巧将一个手指弄破了。因此他的父亲,当时的皇帝,就下了一道敕令,命令全体臣民吃鸡蛋时打破鸡蛋较小的一端,违令者重罚。老百姓们对这项命令极其反感。历史告诉我们,由此曾经发生过6次叛乱,其中一个皇帝送了命,另一个丢了王位。这些叛乱大多都是由Blefuscu的国王大臣们煽动起来的。叛乱平息后,流亡的人总是逃到那个帝国去寻求避难。据估计,先后几次有11000人情愿受死也不肯去打破鸡蛋较小的一端。关于这一争端,曾出版过几百本大部著作,不过大端派的书一直是受禁的,法律也规定该派任何人不得做官。”

1980年,丹尼·科恩(Danny Cohen),一位网络协议的早期开发者,在其著名的论文"On Holy Wars and a Plea for Peace"中,为平息一场关于字节该以什么样的顺序传送的争论,而第一次引用了该词。

总结

引用维基百科的一段话:在哪种字节顺序更合适的问题上,人们表现得非常情绪化,实际上,就像鸡蛋的问题一样,没有技术上的原因来选择字节顺序规则,因此,有关大小端的争论沦为关于社会政治问题的争论,只要选择了一种规则并且始终如一地坚持,其实对于哪种字节排序的选择是任意的。

参考资料

文章分类
iOS
文章标签