64位主机字节序与网络字节序之间的转换
C字节序转换
常用的函数有
函数 | 功能 |
---|---|
ntohs | 将一个无符号短整形数从网络字节顺序转换为主机字节顺序。 |
htons | 将无符号短整型主机字节序转换为网络字节序 |
ntohl | 将一个无符号长整形数从网络字节顺序转换为主机字节顺序。 |
htonl | 将无符号长整型网络字节序转换为主机字节序 |
以上函数对应的是 16 位、 32 位长的数据。
64位主机字节序与网络字节序转换
这个需求没有标准的函数实现,需要手动实现一个。
分析一下,一个 64 位的 long long 型数据,它在主机字节序是怎么存储的:
long long a = 0X123456789abcdef0
在内存中它的存储应该是(小端的话)
f0 de bc 9a 78 56 34 12
//内存由低到高的增长顺序
那转成大端,应该是:
12 34 56 78 9a bc de f0
//内存由低到高的增长顺序。
当然是需要借助 ntohl htonl 这两个函数来实现,可以把 long long 拆成两个 int 型的数(high 和 low)。
比如 0X123456789abcdef0,就可以拆成 high: 0X12345678,low:0X9abcdef0。
得到的结果应该是:0Xf0debc9a78563412,这个 64 位数也可以拆成 high 和 low;high:0Xf0debc9a,low:0X78563412。
可以发现:
网络序的 high 是 主机序的 low 转网络序
网络序的 low 是主机序的 high 转网络序
就可以写出以下代码:
#define __int64 long long
__int64 ntoh64(const __int64 val )
{
long high, low;
low = (long)(val & 0x00000000FFFFFFFF);
high = val >> 32;
high = (long)(high & 0x00000000FFFFFFFF);
low = ntohl( low );
high = ntohl( high );
__int64 nRet = 0;
nRet = low;
nRet <<= 32;
nRet |= high;
return nRet;
}
不过这个代码只适用用主机序为小端字节序的,如果主机序本身就是大端的话,与网络序一样,是不用修改的。再完善一下代码。
#define __int64 long long
int isBigEndian()
{
union
{
short s;
char c[sizeof(short)];
} un;
un.s = 0x0102;
if(sizeof(short) == 2)
{
if(un.c[0] == 1 && un.c[1] == 2)
{
return 1;
}
else if (un.c[0] == 2 && un.c[1] == 1)
{
return 0;
}
else
{
printf("unknown\n");
return 0;
}
}
else
{
printf("sizeof(short)= %d\n",sizeof(short));
return 0;
}
return 0;
}
__int64 ntoh64(const __int64 val )
{
int ret = isBigEndian();
if(1 == ret)
{
return val;
}
long high, low;
low = (long)(val & 0x00000000FFFFFFFF);
high = val >> 32;
high = (long)(high & 0x00000000FFFFFFFF);
low = ntohl( low );
high = ntohl( high );
__int64 nRet = 0;
nRet = low;
nRet <<= 32;
nRet |= high;
return nRet;
}
同理 hton64 可以与 ntoh64 一样写法。这里就不赘述了。