字节序(endianness)
这篇文章来自于对How to teach endian的理解
One of the major disciplines in computer science is parsing/formatting. This is the process of converting the external format of data (file formats, network protocols, hardware registers) into the internal format (the data structures that software operates on).
解析和格式化是计算机科学中主修科目之一,它是外部数据(如文件格式、网络协议、硬件寄存器等)和内部数据(软件运行时的数据结构)相互转化的过程。
大于255的整数需要使用另外的字节进行数据表示,这些字节摆放、读取的顺序就成为字节序。
计算机硬件有两种存储数据的方式:大端字节序(big endian)和小端字节序(little endian)。
假如有一个数值为0x1234的数,高位是0x12(这里是一个字节),低位是0x34(一个字节)。
大端字节序:高位字节在前,低位字节在后。这个数字被存放为0x1234。
小端字节序:低位字节在前,高位字节在后。这个数字被存放为0x3412。
大端字节序的顺序适合人们处理数字的方式。那么为什么要使用小端字节序呢?
这是因为小端字节序的效率比大端字节序要高,在计算机电路中,先对低字节数据进行处理。
那么外部数据如何转化成内部数据(解析)的呢?
有两种方式 buffered or streaming 缓存和流。
-
在缓存模型中,首先读取整个输入,然后再进行解析
-
在流模型中,是一个字节读取并解析,再进行下一个字节。
流模式最适合非常大的文件或跨TCP网络连接的流数据。
缓存模型:首先假设你将文件数据读取到了一个buffer数组中,然后
你要解析大端字节序整数x,那么
x = buffer[offset] * 256 + buffer[offset + 1]
也可以写成 x = buffer[offset] << 8 | buffer[offset + 1]
你要解析小端字节序整数y,那么
y = buffer[offset + 1] * 256 + buffer[offset]
也可以写成 x = buffer[offset + 1] << 8 | buffer[offset]
很明显大端字节序是将高位的(offset小的)放在了前面。
在Linux的头文件<netinet/ip.h>的数据结构中也可以看到。
struct ip {
#if BYTE_ORDER == LITTLE_ENDIAN
u_char ip_hl:4, /* header length */
ip_v:4; /* version */
#endif
#if BYTE_ORDER == BIG_ENDIAN
u_char ip_v:4, /* version */
ip_hl:4; /* header length */
#endif
u_char ip_tos; /* type of service */
short ip_len; /* total length */
u_short ip_id; /* identification */
short ip_off; /* fragment offset field */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
如果想了解更多,可以在原文中查看。