一、字节序,为字节的顺序,就是大于一个字节类型的数据在内测中的存放循序,一个字节的数据
当然就没有顺序可言了。
二、大端序与小端序
字节序分为两类:Big-Endian 和 Little-Endian。
1、Little-Endian(小端序)就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2、Big-Endian(大端序)就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
unsigned int整形数据0X12345678为例,其大端序、小端序的存储内容如图所示:
如0X01000000就为内存的低地址端,0x01000003就为内存的高地址端
而数据0x12345678左边为高位字节,右边的为低位字节,也就是说0x12位高位字节,
0x78为低位字节
unsigned int i= 0x12345678; unsigned char* p = (unsigned char*)&i; printf("%x\n", p[0]); //打印出16进制的78 printf("%x\n", p[3]); //打印出16进制的12
如代码所示,对i的地址进行类型转换,指针p指向的是i在内存中的低地址端的位置,又因为这台店内内
存中存储数据是以小端序类存储的,所以内存辞职端存的是低位字节,所以怕p[0]以16进制来打印,打印
出78,p[3]打印出12。在一个数组中arr[4]中,arr[0]是低地址端,arr[3]是高地址端。
三、网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次是8~15bit,然后是16~23 bit,
最后是24~31 bit,这种传输次序称作大端序字节,友谊TCP/IP首部中所有的二进制整数在网络中传输是都要
以这种次序,因此他又称作网络字节序,比如,以太网头部中2字节的“一台网帧类型”,标识后面数据的类型。
UDP/TCP/IP协议规定:把接收到的的第一个字节当做高位字节来看待,这就要求发送端发送的第一个字节是
高位字节;而在发送端发送数据时,发送的第一个字节是该数值在内存中起始地址(低地址)对应的那个字节,
也就是说,该数值在内存中的起始地址处对应的那个字节就是要发送的第一个高位字节(即:高位字节存放在
低地址处);
由此可见,多字节数值在发送之前,在内存中应该是以大端序存放的;所以说,网络字节序是大端字节序;比
如我们经过网络发送整形数值0x12345678时,在80X86平台中,它是以小端序存放的,在发送之前需要使用系
统提供的字节转换函数htonl()将其转换成为大端序存放的数值。对于ARP请求或应答的一台网帧类型来说,在
网络传输时,发送的顺序是0x08,0x06。
四、内存空间中的相关布局
关于内存空间布局情况的说明:
| 栈底
.
. 栈
.
栈顶
-----------------------
|
|
\|/
|
|
-----------------------
堆
-----------------------
未初始化的数据
----------------(统称数据段)
初始化的数据
-----------------------
正文段(代码段)
----------------------- 最低内存地址 0x00000000
栈底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
栈顶 (低地址)
以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value:Big-Endian: 低地址存放高位,如下图:
栈底 (高地址)
---------------
buf[3] (0x78) -- 低位字节
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位字节
---------------
栈顶 (低地址)
栈底 (高地址)
---------------
buf[3] (0x12) -- 高位字节
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位字节
---------------
栈顶 (低地址)
————————————————
版权声明:本文为CSDN博主「寂寂寂寂寂蝶丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/SwordArcher/article/details/82417429
1 bool isLittleEndian() 2 { 3 unsigned int i = 0x12345678; 4 unsigned char* c = (unsigned char*)&i; 5 return(*c == 0x78); //判断是否是低位字节存内存低地址 *c取得就是内存中存放i的低地址 6 }
(2)通过联合体判断(返回真则为小端序,返回假则为大端序)
1 bool isLittleEndian() 2 3 { 4 union 5 6 { 7 int i; 8 9 char c; 10 11 }udata; 12 udata.i = 1; 13 14 return(udata.c == 1); 15 }
(3)linux环境下,通过htonl等函数直接判断
1 #include <arpa/inet.h> 2 3 bool isLittleEndian() 4 5 { 6 7 return (1 != htonl(1)); 8 9 }
七、大小端的转换
//短整型大小端互换#define BigLittleSwap16(A) ((((uint16_t)(A) & 0xff00) >> 8 ) | \\ (((uint16_t)(A) & 0x00ff) << 8 )) //长整型大小端互换#define BigLittleSwap32(A) ( (((uint32_t)(A) & 0xff000000) >> 24) | \\ (((uint32_t)(A) & 0x00ff0000) >> 8 ) | \\
(((uint32_t)(A) & 0x0000ff00) << 8 ) | \\ (((uint32_t)(A) & 0x000000ff) << 24))
结合判断大小端的函数,如果本机是大端,则可以直接返回,如果本机是小端,则需要进行字节序的
转换,或者进行网络数据的转换,在返回
uint16_t htons(uint16_t hostshort);//16位的主机字节序转换到网络字节序
uint32_t ntohl(uint32_t netlong);//32位的网络字节序转换到主机字节序
uint16_t ntohs(uint16_t netshort);//16位的网络字节序转换到主机字节序
————————————————
版权声明:本文为CSDN博主「寂寂寂寂寂蝶丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/SwordArcher/article/details/82417429