在几乎所有机器上,多字节对象都被存储为连续的字节序列,对象的地址为所使用字节中最小的地址。例如,假设一个类型为int的变量x地址为0x100,也就是说地址表达式&x的值为0x100。那么,x的4个字节将被存储在存储器的0x100、0x101、0x102和0x103的位置。
那么,如果这个变量的值为0x01234567的话,是0x01被保存在0x100,还是0x67被保存在0x100呢?这就所谓的大小端字节序的问题。
假如机器选择在存储器中按照从最低有效字节到最高有效字节的顺序存储对象,则称为小端字节序(little endian)。即将0x01234567中低位的值0x67存储在地址低位的0x100上,存储值位的增长方向与地址的增长方向是一致的,如下所示,这比较符合我们逻辑直觉。

假如机器选择在存储器中按照从最高有效地址到最低有效地址的顺序存储对象,则称为大端字节序(big endian)。即将0x01234567中高位的值0x01存储在地址低位的0x100上,存储值位的增长方向与地址的增长方向是相反的,如下所示,这比较符合我们的视觉直觉。

两种字节序都是差不多的,并没有哪种比较好。但是从我个人的看法,结合以前用过可扩展位图来记录一些东西的经历,我更偏向于小端字节序,在使用中也会更好。例如用char数组来记录几千个id中第x个id被用了,那就是先x/8来得到对应要设置的位在数组中的索引,显然x越小,索引值越小,也就是越靠近数组开始的地方,这不就是与小端字节序是一样的嘛。而且这样子也很容易拓展,毕竟地址正常的生长方向都是从小到大往右生长的。
由于字节序是由主机决定的,所以同一主机内的对于同一段数据解释是不会出现问题的。但是如果涉及到网络通信,这个时候两端的两台主机可能一台是小端字节序而另一台是大端字节序,那就会导致通信出现问题,因为解析方式已经是错的了。所以就需要对网络通信中的字节序进行约定,即网络字节序。网络字节序采用的是大端字节序。所有主机在通过网络发送内容时,会先将内容转换位网络字节序再发送出去,而接受到内容时则会先将其转换为本地的字节序再处理。
那我们怎么可以知道本地主机是大端字节序还是小端字节序呢?方法很简单,将0x01234567保存到int变量x中,在将其转换位char数组,如果数组第一个值是0x01,那就是大端的,而如果是0x67,则说明是小端的了。
#include <stdlib.h>
#include <stdio.h>
int main()
{
int x = 0x01234567;
char *c = (char *)&x;
if (c[0] == 0x01)
printf("big endian\n");
else
printf("little endian\n");
return 0;
}