通俗易懂说字节序,大小端,网络序和主机序
1. 什么是字节序
字节序:
顾名思义字节的顺序,
就是大于一个字节类型的数据在内存中的存放顺序。
一个字节的数据没有顺序的问题了。
如: char 类型数据占1字节,没有字节序问题
但是 int 占4字节,故int类型数据在传输过程中就需要考虑字节序的问题。
1.1 为什么字符串不用转序
例子:
char acName[32];
memset(acName, 0, sizeof(acName));
strlcpy(acName, "hani", sizeof(acName));
不用转序传输到网络……
接收……
因为:
字符串中的每个字符如'h','a','n'等都是占一个字节。
就没有字节序的问题了。
而 int a = 4; //a占4个字节就涉及字节序了。
2. 什么是网络字节序
网络字节序:
TCP/IP各层协议将字节序定义为Big-Endian,
因此TCP/IP协议中使用的字节序通常称之为网络字节序。
4个字节的32 bit值以下面的次序传输:
高字节--------------------------------------低字节
首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。
这种传输次序称作大端字节序。
由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序
3. 什么是主机字节序
3.1 主机字节序
通常我们说的主机序(Host Order)就是遵循Little-Endian规则
就是我们平常说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。
3.2 大小端字节序
标准的Big-Endian和Little-Endian的定义如下:
a) Little-Endian 小端
就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian 大端
就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
4. 举例
数据: 0x1234 大小端传输:
在十进制中我们都说靠左边的是高位,靠右边的是低位,在其他进制也是如此。就拿 0x1234来说,从高位到低位的字节依次是0x12、0x34。
其中,地址 0x00 是低地址,0x01是高地址。
地址: 0x00 0x01
大端: 12 34
小端: 34 12
4.1 主机序代码例子说明
//定义
typedef struct stTest{
……
UINT uiID;/*ID */
UINT uiLoadId;
UINT uiWhoisSum;
UINT uiFileWhoisSum;
……
}
//赋值
stTest pstItem;
……
pstItem->uiID = XX_INVALID_INSTANCE_ID; //(0xffffffff)
pstItem->uiLoadId = XX_FILELOAD_MAX; //3
pstItem->uiWhoisSum = 0;
pstItem->uiFileWhoisSum = 2;
//看内存
(gdb) x /32x &pstItem->uiID
//内存地址升高b0 b1 b2 b3 b4 b5 b6 b7
0xfc62b0: 0xff 0xff 0xff 0xff 0x03 0x00 0x00 0x00
0xfc62b8: 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00
0xfc62c0: 0x32 0x32 0x32 0x33 0x00 0x00 0x00 0x00
0xfc62c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
(gdb)
由此可以看出:uiLoadId 的值3,0x00 00 00 03低字节存放在低地址处,是小端序
5. 判断一个体系结构是 big-endian 还是 little-endian
5.1 简单方法:
直接打印代码中的大于一个字节的值即可:(如int类型值)
小端序:
//同上,看内存
//小端序设备
(gdb) x /32x &pstItem->uiID
//内存地址升高b0 b1 b2 b3 b4 b5 b6 b7
0xfc62b0: 0xff 0xff 0xff 0xff 0x03 0x00 0x00 0x00
0xfc62b8: 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00
0xfc62c0: 0x32 0x32 0x32 0x33 0x00 0x00 0x00 0x00
0xfc62c8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
(gdb)
大端序:
//大端序设备
(gdb) x /32x &pstItem->uiID
0x12f70dfe0: 0xffffffff 0x00000003 0x00000000 0x00000000
0x12f70dff0: 0x32323200 0x00000000 0x00000000 0x00000000
……
5.2 复杂方法:
int x = 1; /* 32位 二进制 00000000 00000000 00000000 00000001 */
/*
* 内存地址方向: 高位 <--------------------> 低位
* little-endian 表示: 00000000 00000000 00000000 00000001
* big-endian 表示: 00000001 00000000 00000000 00000000
*/
if (*(char *) &x == 1) /* 这里把int型转为char型, 相当于只取了int型的最低8bit */
/* little-endian */
else
/* big-endian */
5.3 一般来说:arm和x86架构是小端序,mips架构是大端序
https://www.cnblogs.com/straight/articles/7660889.html
https://blog.csdn.net/yusiguyuan/article/details/48222789/
6. 源码实现
通俗易懂说字节序,大小端,网络序和主机序(2)htonl和ntohl 源码实现
https://blog.csdn.net/lqy971966/article/details/106468789