大、小端模式的说法,来自乔纳森·斯威夫特的小说《格列夫游记》,在小人国内部分裂成 Big-endian 和 Little-endian 两派,他们的争论在于一派要求从鸡蛋的大头把鸡蛋打破,另一派要求从鸡蛋的小头把鸡蛋打破。斯威夫特借以讽刺英国的政党之争,而计算机工业则借此表示数据储存顺序的分歧。
  大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
  记忆方法: 地址的增长顺序与值的增长顺序相反。
  小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
  记忆方法: 地址的增长顺序与值的增长顺序相同。

  那么,为什么会有大小端模式之分呢?
  这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址(即0x0010)中,0x22放在高地址中(即0x0011)中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以随时在程序中(在ARM Cortex 系列使用REV、REV16、REVSH指令)进行大小端的切换。
  如此说来,大小端模式就是处理器在内存中对多字节数据进行存取的不同方式。注意两点:一是处理器,大小端模式是处理器的差异造成的;二是多字节数据,也就是说只有处理器操作的数据类型超过一个字节时才会存在大小端模式的问题,而操作char类型数据是不存在该问题的。
  
  字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。字节序与大小端模式的概念相似,我们上面所说的就是在计算机内存中存储的字节顺序问题(即主机字节序),此外还存在网络传输中的字节顺序问题(即网络字节序)。
  
  那么,为什么会存在网络字节序呢?
  我们知道,网络传输上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,就需要考虑先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢?实际上,接收端收到的第一个字节会被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端模式存放。

  网络字节序是 TCP/IP 中规定好的一种数据表示格式,它与具体的 CPU 类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。好了,我们需要记住,网络字节序是一种规定,它采用的是大端模式(Big-endian)。
  
  在网络程序开发或是跨平台开发时,就需要注意字节序的问题了。应该保证只用一种字节序,否则两方的解释不一样就会产生错误。为了方便开发,BSD socket 提供了以下四个转换函数:
  ​​​htons​​​ 把 ​​unsigned short​​​ 类型从主机序转换到网络序
  ​​​htonl​​​ 把 ​​unsigned long​​​ 类型从主机序转换到网络序
  ​​​ntohs​​​ 把 ​​unsigned short​​​ 类型从网络序转换到主机序
  ​​​ntohl​​​ 把 ​​unsigned long​​​ 类型从网络序转换到主机序
  在使用 Little-endian 的系统中,这些函数会把字节序进行转换;而在使用 Big-endian 的系统中,这些函数会定义成空宏。
  看到这里,就会想:为什么只有 short 和 long 类型?对于 float 和 double类型怎么处理?要是遇到64位系统怎么办?
  有网友说:htons 和 htonl 是因为 TCP/IP 的一些参数用到 int 和 long,但没有 float 和 double 的参数。另外,float 和 double,与 CPU 无关。一般编译器是按照 IEEE 标准解释的,即把 float/double 看作4/8个字符的数组进行解释。因此,只要编译器是支持IEEE浮点标准的,就不需要考虑字节顺序。
  大家注意到,这里说不需要转换,也是有条件的。我没有考证过例外情况的存在比例,但是我相信在绝大部分情况下,编译器都是符合IEEE标准的。如果你实在不放心,可以采取下面两种办法:
  (1) 在保证不超过int范围的情况下,将浮点数乘以100(或1000,10000,视所需精度随你定)转换为整数传输,在接收端再除以100,得到浮点数。

  此外,我们还会听到 Java字节序,Java字节序与网络字节序一样,采用大端模式。不是说大小端模式只跟 CPU 有关吗?也就是说不同的计算机系统采用不同的字节序存储数据,一种 CPU 不是 Big-endian 就是Little-endian。那这个 Java字节序到底是什么鬼?
  Java 程序员是幸福,因为相对于 C/C++ 的不跨平台,JVM 为开发人员屏蔽了大量的底层细节和复杂性,从而能够将精力放在实现特定的业务逻辑上,因此 JVM 规定了数据的存储顺序(即大端模式)。所以做 Java 程序开发完全可以忽略字节序的存在,甚至有些 Java 程序员根本没听过字节序的概念。