字节序问题
常用术语
网络字节序:network byte order
主机/本地字节序:host byte order
大端字节序:big endian
小端字节序:small endian
什么是大端/小端字节序呢?
先理解什么是高位什么低位.
假设一个变量a = 0xdeadbeef,那么如果按照字节的位数来理解的话,左边就是高位,右边就是低位,可能还比较模糊,比如我们说这里有1000个苹果(十进制),那么从左边的1开始就是高位,右边就是低位,因为最左边的1实际上代表的是一千个最左边的1.这个规律适用于所有数制.
好了,现在可以说大端小端了.
大端就是低位对低位,高位对高位,与我们人类的常识中对数字的理解是一致的.这是什么意思呢? 数字中的低位对应低位的地址,数字中的高位对应高位的地址. 还是a = 0xdeadbeef ,
地址 | 变量a |
---|---|
0x00地址中的低位,低是小的意思 | 0xef |
0x01 | 0xbe |
0x02 | 0xad |
0x03地址中的高位 | 0xde |
小端则与大端完全颠倒,低位对高位,高位对低位.
需要注意的是,只是字节的顺序颠倒了,而字节中的二进制位是不变的,这也是为什么叫做字节序而不是"位序"的原因
网络字节序与主机字节序
网络字节序就是大端字节序
主机根据不同的机器会有不同的结果,可能是大端,也可能是小端,但是以小端更为普遍.
实践测试
环境: centos7 64
代码:
#include <stdio.h>
#include <arpa/inet.h>
#define TRUE 0
#define FALSE -1
int is_small_endian(void)
{
uint32_t t = 0xdeadbeef;
uint8_t* p = (uint8_t*)&t;
if(*p == 0xef)return TRUE;
else if(*p == 0xde)return FALSE;
}
int main()
{
uint32_t a = 0xdeadbeef;
printf("a: 0x%08x
",a);
if(is_small_endian()==TRUE)printf("small endian
");
else printf("big endian
");
//if the machine is little end,then 'a' will be reversed by bytes
uint32_t net_a = htonl(a);
printf("net_a: 0x%08x
",net_a);
uint32_t net__to_local_a = ntohl(a);
printf("net_to_local_a: 0x%08x
",net__to_local_a);
return 0;
}
结果:
a: 0xdeadbeef
small endian
net_a: 0xefbeadde
net_to_local_a: 0xefbeadde
一个有趣的现象
ntohl(123)与htonl(123)的结果是一样的,无论其主机字节序是什么.
如果主机字节序是小端,那么ntohl(123)将是123的大端字节序
如果主机字节序是大端,那么ntohl(123)将是123的大端字节序
从这里可以推测ntohl(),htonl()函数的逻辑,先判断主机的字节序,如果是小端,那么就翻转;如果是大端,那么就保持不变