大端及小端的简析
- 序言
- 环境
- 概念
- 理解可能有问题的地方
- 一般情况下需要注意的大小端情况
- 关于大小端相关的实用函数/代码
- 判断自身大小端的代码
- 大小端转换函数
序言
我记得我已经查过4次了,最近回想一下发现我竟然又忘了!所以特以此文来记录一下。
环境
Qt5.14.2 MSVC2017 64bit(VS2019)
概念
大端模式(Big-endian):高位字节存低位地址,低位字节存高位地址
小端模式(Little-endian):低位字节存低位地址,高位字节存高位地址
举个例子:
数值: 0x12345678
存的内存位置:0x000000D3B8EFF254
~ 0x000000D3B8EFF257
大端在内存中分别存的:12 34 56 78
小端在内存中分别存的:78 56 34 12
0x12 34 56 78
,其高位字节就是越左越高,低位字节就是越右越低;
0x000000D3B8EFF254
~ 0x000000D3B8EFF257
,其高位地址就是数值越高就高,其低位地址就是数值越低就低;
在0x000000D3B8EFF254
低位地址里,存储0x12
的则是大端模式,存储0x78
的则是小端模式。
理解可能有问题的地方
0x12 34 56 78
共4个字节,每个字节大端和小端存的都是一样的,这个没什么区别,意思是0x78的十六进制,同样都是以0b0111 1000二进制的存放方法,不会说大端模式就0001 1110这样存的,不是这个意思,大小端区别是按字节为单位判断的。- 有些人可能理解了十六进制
0x12345678
为例子时的大小端情况,就不清楚十进制ulong,char数组,std::string等非十六进制情况时大小端情况,如果有这种疑惑说明你对数据的本质不清楚,这些在内存中存放的实质上就是一个个组合成的二进制数或者是十六进制数,字母可以用ASCII对照转换成十六进制数,中文字符可以用Unicode来对照转换成十六进制数。
一般情况下需要注意的大小端情况
TCP/IP协议规定必须采用网络字节顺序NBO(Network Byte Order),即大端模式。
而主机字节顺序(HBO,Host Byte Order)则看所在的CPU处理器及编译器才能确定,而不是看操作系统。
但是普遍常见的CPU是小端模式。
关于大小端相关的实用函数/代码
判断自身大小端的代码
union myunion
{int a;char b;
};// 如果是小端模式则返回1,大端模式则返回0
bool is_little_endian(void)
{union myunion u1;u1.a = 0x12345678; // 地址0的那个字节内是0x78(小端)或者0x12(大端)if(0x78 == u1.b)return true;else if(0x12 == u1.b)return false;
}
大小端转换函数
头文件:
windows: #include <WinSock2.h>
linux: #include <arpa/inet.h>1)htonl-》Host to Network Long函数原型:uint32_t htonl (uint32_t hostlong)
函数返回值:是一个32位的网络字节顺序。
函数的作用:是将一个32位数从 主机字节顺序 转换成 网络字节顺序。注:无符号的长整型 在 32位的系统是 4字节。2)htons函数原型:uint16_t htons (uint16_t hostshort)
函数返回值:是一个16位的网络字节顺序。
函数的作用:是将一个16位数从 主机字节顺序 转换成 网络字节顺序。注:无符号的短整型 在 32位的系统是 2字节。3)ntohl Network to Host Long函数原型是:uint32_t ntohs (uint32_t netlong)
函数返回值:是一个32位的主机字节顺序。
函数的作用:是将一个32位数由 网络字节顺序 转换为 主机字节顺序。4)ntohs 函数原型是:uint16_t ntohs (uint16_t netshort)
函数返回值:是一个16位的主机字节顺序。
函数的作用:是将一个16位数由 网络字节顺序 转换为 主机字节顺序。等...
因个人尚未读到这些函数的源码,所以只清楚上述的函数中是知道主机字节顺序是小端的,不确定自身CPU如果是大端模式会不会自行判断。