字节序
计算机上的数据在内存中是以1 字节(Byte)为单位存储的,1Byte = 8bits, 这是因为电子计算机ROM的最小信息单位是bit, 而CPU的数据总线一般为8根,即一次可读取1Byte.
对于长度为1Byte的char型,不存在字节序的问题。而对于长度大于1Byte的数据类型,就存在字节序的问题。
大、小端字节序
大端字节序: 高位字节数据存放在内的低地址处,低位数据存放在内的高地址处;
小端字节序: 高位字节数据存放在内的高地址处,低位数据存放在内的低地址处;
以长度为4字节的int型为例,0x12345678的十进制为305419896, 如果是大端字节序的机器,它在内存中的存放为:
低地址 -------------> 高地址
0x12 | 0x34 | 0x56 | 0x78
而在小端字节序的机器上,则为
从低地址到高地址: 78 56 34 12
这两个概念很容易搞混,有如下巧记法:
一般网络字节序为大端字节序,因为UDP/TCP/IP协议规定:把接收到的第一个字节当作高位字节看待,网络数据解析时先收到的数据存放于低地址,否则内存的访问将是不连续的。 所以,大端字节序 = 网络字节序 = 高位放低地址。
大小端机器检测
我们常用的X86结构是小端模式,而几种检测的方法:
- 直接取低地址字节
BOOL IsBigEndian()
{
int a = 0x1234;
char b = *(char *)&a; //通过将int强制类型转换成char单字节,通过判断起始存储位置。即等于 取b等于a的低地址部分
if( b == 0x12)
{
return TRUE;
}
return FALSE;
}
- 使用union
BOOL IsBigEndian()
{
union NUM
{
int a;
char b;
}num;
num.a = 0x1234;
if( num.b == 0x12 )
{
return TRUE;
}
return FALSE;
}
大小端类型转换
2字节和4字节
template<typename T>
constexpr
typename std::enable_if<std::is_same<T, uint32_t>::value, uint32_t>::type
swap (T value) noexcept
{
return ((value & 0x000000FF) << 24)
| ((value & 0x0000FF00) << 8)
| ((value & 0x00FF0000) >> 8)
| ((value & 0xFF000000) >> 24);
}
template<typename T>
constexpr
typename std::enable_if<std::is_same<T, uint16_t>::value, uint16_t>::type
swap (T value) noexcept
{
return ((value & 0x00FF) << 8)
| ((value & 0xFF00) >> 8);
}
8字节
# define swap_64(x) \
(__extension__ ((((x) & 0xff00000000000000ull) >> 56) \
| (((x) & 0x00ff000000000000ull) >> 40) \
| (((x) & 0x0000ff0000000000ull) >> 24) \
| (((x) & 0x000000ff00000000ull) >> 8) \
| (((x) & 0x00000000ff000000ull) << 8) \
| (((x) & 0x0000000000ff0000ull) << 24) \
| (((x) & 0x000000000000ff00ull) << 40) \
| (((x) & 0x00000000000000ffull) << 56)))
参考:
https://blog.youkuaiyun.com/qq_27384769/article/details/80700320
https://blog.youkuaiyun.com/dange4/article/details/80277898