字节序#
字节序:存放字节的顺序。
字节序与 CPU 架构相关,通常 x86 架构使用小端序,字节序决定数据在内存中存储的顺序。
在网络通信传输数据时需要统一字节序,以确保能够正常的传输和解析数据。
存储数据方式有:大端序(Big-Endian)和 小端序(Little-Endian)。
大端序:高位字节存储在低地址,低位字节存储在高地址(低对高)。
小端序:高位字节存储在高地址,低位字节存储在低地址(低对低)。
对于 0x1234
十六进制的数,12
是高位字节,34
是低位字节。而高地址和低地址指的是地址的大小,例如有两个地址 0x1010
和 0x1011
,0x1010
就是低地址,0x1011
就是高地址。
判断本机字节序#
// 1 Byte = 8 bit(8 位二进制代表一个字节)
// 1 位十六进制代表 4 bit
// short 占 2 Byte = 16 bit
// char 占 1 Byte = 8 bit
// 强转为 char *,后取出的首地址(低位地址)占 1 Byte
// 将这个低位地址解引用后转为 short
// 与原始数据中的低位和高位进行比较
// 如果等于高位则说明为大端序(低对高)
// 如果等于低位则说明为小端序(低对低)
// 如果是大端序,低地址存储数据的高位字节
// 高位字节是 0x12
// &i 取出的是低地址
// (short)*(char *)&i == 0x12
bool isBigEndian() {
short i = 0x1234;
return (short)*(char *)&i == 0x12;
}
// 如果是小端序,低地址存储数据的低位字节
// 低位字节是 0x34
// &i 取出的是低地址
// (short)*(char *)&i == 0x34
bool isLittleEndian() {
short i = 0x1234;
return (short)*(char *)&i == 0x34;
}
简单写法:
bool isBigEndian() {
short i = 1;
return *(char *)&i != 1;
}
转换本机字节序与网络字节序#
网络字节序通常使用大端字节序。
POSIX API#
// host to network unsigned short
htons();
// host to network unsigned long
htonl();
// network to host unsigned short
ntohs();
// network to host unsigned long
ntohl();
Boost Asio API#
// host to network unsigned short
boost::asio::detail::socket_ops::host_to_network_short();
// host to network unsigned long
boost::asio::detail::socket_ops::host_to_network_long();
// network to host unsigned short
boost::asio::detail::socket_ops::network_to_host_short();
// network to host unsigned long
boost::asio::detail::socket_ops::network_to_host_long();
在使用这些 API 时,应该确保输入参数和返回结果都是无符号整型,否则可能存在符号拓展问题。