一直以来我们在字节序做转换的时候,大多是查的相关的函数,当然这些函数都能解决你的问题,但对原理可能理解大概有点模糊,面试时深入点可能就会回答不完整。写这遍文章原因是在看代码调试过程中遇到网络字节序要转主机字节序,通常的方法写测试代码,现在简单介绍另外一种测试方法《计算器》--程序员 版,顺带了解转换原理。
先了解操作系统常用的存储方法:
小端字节序:低字节存于内存低地址;高字节存于内存高地址;(符合正常思维逻辑)
大端字节序:高字节存于内存低地址;低字节存于内存高地址;(有点B格,用到最多是网络数据传输时)
下面我们以网络端口为例讲下转换过程: 主机 6000(小端) --> 网络 28695(大端)
DEC: 6000 , HEX :1770, BIN:0001 0111 0111 000
存储原理: 整数存储按最小存储单元为 四字节,分高位二字节,低位二字节【二字节分高低各8位】
简单版: 低位二字节在高低字节内转换 (高低字节:高8bit,低8bit) ,验证函数:htons()
1、 一字节:以 整数1为例 =====> (一般存低位二字节的低8位【低4位上】)
整数1 :00000000 00000001 , 按简单版转换方法 ==> 00000001 00000000 (256)
2、一字节:以 整数32为例 =====> (一般存低位二字节的低8位【高4位上】)
整数32:00000000 00100000,按简单版转换方法 ==> 00100000 00000000 (8192)
3、二字节:(一般存低位二字节上【 分高8位,低8位】 )
按实例整数6000分析:将高八位(8bit)与低八位换位(8bit)
0001 0111 0111 000 按二字节描述转换 ==> 0111000 00010111 (7017) ===>28695
额外加一个整数,留意转换结果:
整数512 : 00000010 00000000 ,同理按上面方法 ==> 00000000 00000010 (2)
加强版:占用三个字节或四个字节,转换过程有点变化,占用高二字节,低二字节
4、三字节:(一般存高位的低二字节【低4位上】和低位二字节上),验证函数:htonl()
整数 65539:(实际存储,往下) ===> 50331904
高位: 00000000 00000000 00000000 00000001
低位: 00000000 00000000 00000000 00000011
过程1:先高位与低们转换位置 (往下)
高位: 00000000 00000000 00000000 00000011
低位: 00000000 00000000 00000000 00000001
过程2:再在高位中进行二字节高低字节转换(低位同方法)
高位: 00000000 00000011 00000000 00000000
低位: 00000000 00000001 00000000 00000000
针对加强版附上图片分析,主要是有两个过程更有助于理解:
转换过程1:先高低二字节转换,未完
转换过程2 :再分别在二字节中进行,高低位转换,OK,最终完成。当然四字节的数跟三字节一样,暂时不分析。
超强版:8字节64位,这种情况在网络传输数据中也遇到过,当然系统好像没有针对性的函数,下面贴出网友贡献出来的函数。
优点:做了适配系统。(网上一大把,推荐这种方式)
unsigned long long ntohll(unsigned long long val)
{
if (__BYTE_ORDER == __LITTLE_ENDIAN)
{
return (((unsigned long long )htonl((int)((val << 32) >> 32))) << 32) | (unsigned int)htonl((int)(val >> 32));
}
else if (__BYTE_ORDER == __BIG_ENDIAN)
{
return val;
}
}
unsigned long long htonll(unsigned long long val)
{
if (__BYTE_ORDER == __LITTLE_ENDIAN)
{
return (((unsigned long long )htonl((int)((val << 32) >> 32))) << 32) | (unsigned int)htonl((int)(val >> 32));
}
else if (__BYTE_ORDER == __BIG_ENDIAN)
{
return val;
}
}