字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处;大端字节序是高字节数据存放在低地址处,低字节数据存放在高地址处。
简介
基于X86平台的PC机是小端
字节序的,而有的嵌入式平台则是
大端字节序的。因而对int、uint16、uint32等多于1字节类型的数据,在这些嵌入式平台上应该变换其存储顺序。通常我们认为,在空中传输的字节的顺序即网络字节序为标准顺序,考虑到与协议的一致以及与同类其它平台产品的互通,在程序中发数据包时,将
主机字节序转换为
网络字节序,收数据包处将网络字节序转换为
主机字节序。
跨平台
在本LINUX的书里介绍到INTEL的CPU使用的小端
字节序其他比MOTOROLA
68000系列CPU使用的是
大端字节序如果不转换 将数据通过网络发出时 比如MOTOROLA发一个16位数据:0X1234 传送到INTEL时
就被INTEL解释为0X3412 也就是4660成了13330 所以有时候需要一些函数来进行大小端字节序的转换
概念
内存里是具体怎么存放的形式?为什么会有CPU解释的不同?数据不是按12345678……这样的顺序一直排列的么?
如: 一个多字节值 0xFECDBA98,内存从地址100开始存放
降序: FE 对应地址100 | CD 对应地址 101 | BA 对应地址 102 | 98 对应地址 103
升序: 98 | BA | CD | FE ---->;same above
注意,我们的书写字数据表示法是从高字节位--->低字节位(从左到右)
内存地址生长方向为: 从左到右 由低到高(这是不变的)
数据为: 0x98BADCFE
降序(Little-endian)
大端字节序存储时 由左到右
升序(Big-endian)小端字节序存储时 由右向左
验证
更简单的调用VC里的checkEndian
Intel处理器的字节顺序是和DEC VAX处理器的字节顺序一致的。因此它与68000型处理器以及Internet的顺序是不同的,所以用户在使用时要特别小心以保证正确的顺序。
任何从Windows Sockets函数对
IP地址和
端口号的引用和传送给Windows Sockets函数的IP地址和端口号均是按照网络顺序组织的,这也包括了
sockaddr_in结构这一数据类型中的IP地址域和端口域(但不包括sin_family域)。
案例1
如何手算主机字节顺序转换为网络字节顺序?假设某16位的整数,主机字节顺序的值是21,那么它的网络字节顺序是多少?解决的步骤是:1、将21化成二进制,二进制,如果不足16位就在其前面补0,补满16位。21转换成二进制是:10101,在它前面补0,补满16位后就得到:00000000#000101012、将这个16位二进制字符平分成两段,每段8位0000000 000010101 == > 00000000#000101013、颠倒这两段的顺序,然后去掉第一个字符“1”前面的0,化成十进制就得到了网络字节顺序的值了。00000000#00010101颠倒后:00010101#00000000即00 01 01 01 00 000000。去掉第一个“1”前面的0得到:10 10 10 00 00 00 0化成十进制得到:5376。
通过这个程序可以进行验证:
编译后,按提示输入ftp和tcp,就得到网络字节顺序值是5376,主机字节顺序值是21。
16位的转换函数:ntohs和htons
ntohs(network to host short)是将网络字节顺序转换为主机字节顺序,返回值是一个16位的整数,即2个字节长度的整数(1字节=8位)short int,也可以写作uint16_t。
htons(host to network short)是将主机字节顺序转换为网络字节顺序,返回值也是一个16位的整数short int。
32位转换函数ntohl和htonl。
ntohl(network to host long)是将网络字节顺序转换为主机字节顺序,返回值是一个16位的整数,即2个字节长度的整数(1字节=8位)long int,也可以写作uint32_t。
htonl(host to network long)是将主机字节顺序转换为网络字节顺序,返回值也是一个16位的整数long int。
IP地址使用的是32位的无符号整数,所以,在对IP地址进行处理的时候,就需要用到32位的转换了。
一个点分十进制的IP地址是192.168.0.1,还原成原来的二进制原码是:
11000000 10101000 0000000 00000 0001
这是主机字符顺序存储的值。
将其按照每个字节分隔开来,即每8位分隔开来,得到:
11000000 10101000 00000000 00000001
将这4段二进制编码进行完全颠倒,就得到了网络字节顺序:
00000001000000001010100011000000
去掉第一个字符“1”前面无效的0,得到:
10 00 00 00 01 01 01 00 01 10 00 00 0
化成十进制得到:16820416
inet_addr函数可以将一个
点分十进制的
IP地址转换成网络字节顺序的长整形十进制值。同样的,inet_ntoa函数将网络字节顺序的长整形十进制数值的IP地址转换成点分十进制。
案例2
分析:用inet_addr函数,转换点分十进制的IP为网络字节顺序的
长整型十进制数值后,再用ntohl函数将其转换成主机字节顺序的长整型整数,然后使用一个自定义函数将这个主机字节顺序的长整形整数转换成二进制。