字节序


字节序是指多字节数据在计算机内存中存储的顺序或者网络传输时各字节的顺序。
在不同的处理器以不同的方式存放, 主要方式有两种即大端字节序(Big Endian)和小端字节序(Little Endian)

端(endian)的起源

“endian” 一词来源于 Jonathan Swift 在1726年写的讽刺小说 “Gulliver’s Travels”(《格利佛游记》)。小说中,小人国为水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开而争论,并由此曾经发生过6次叛乱,其中一个皇帝送了命,另一个丢了王位。争论的双方分别被称为”大端派”和”小端派”。
1980年, Danny Cohen,一位网络协议的早期开发者,在其著名的论文”On Holy Wars and a Plea for Peace”中,为平息一场关于字节该以什么样的顺序传送的争论,而第一次引用了该词。

什么是 Big Endian 和 Little Endian

  • 大端字节序:在内存中,低地址存放数据的高位,高地址存放数据的低位
  • 小端字节序:在内存中,低地址存放数据的低位,高地址存放数据的高位

LE little-endian

最符合人的思维的字节序, 地址低位存储值的低位, 地址高位存储值的高位
因为从人的第一观感来说, 低位值小, 就应该放在内存地址小的地方, 也即内存地址低位; 反之, 高位值就应该放在内存地址大的地方, 也即内存地址高位

BE big-endian

最直观的字节序, 地址低位存储值的高位, 地址高位存储值的低位
不要考虑对应关系, 只需要把内存地址从左到右按照由低到高的顺序写出, 把值按照通常的高位到低位的顺序写出, 两者对照,一个字节一个字节的填充进去

网络字节序

网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。
网络字节序转化为主机字节序时,一定要注意是否需要转换。
htons 把unsigned short类型从主机序转换到网络序
htonl 把unsigned long类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long类型从网络序转换到主机序

在使用little endian的系统中 这些函数会把字节序进行转换
在使用big endian类型的系统中 这些函数会定义成空宏

几个相关的IP网络序互转函数

/* 若成功,返回32位二进制的网络字节序地址;若出错,返回INADDR_NONE */
in_addr_t inet_addr(const char *strptr);

inet_addr 函数转换网络主机地址(如192.168.1.10)为网络字节序二进制值, 如果参数char *cp无效, 函数返回-1(INADDR_NONE), 这个函数在处理地址为255.255.255.255时也返回-1, 255.255.255.255是一个有效的地址, 不过inet_addr无法处理;

/* 返回指向点分十进制数串的指针 */
char* inet_ntoa(struct in_addr inaddr);

inet_ntoa 函数转换网络字节排序的地址为标准的ASCII以点分开的地址, 该函数返回指向点分开的字符串地址的指针, 该字符串的空间为静态分配的, 这意味着在第二次调用该函数时, 上一次调用将会被重写(复盖), 所以如果需要保存该串最后复制出来自己管理.

/* 返回1:串有效,返回0:串出错 */
int inet_aton(const char *strptr, struct in_addr *addrptr);

inet_aton 将一个32位的网络字节序二进制IPv4地址转换为相应的点分十进制数串。