字节顺序

字节顺序

2015年06月23日 10:53:45

阅读数:568

本篇文章主要介绍字节顺序的相关概念和应用,主要面向整数数据和Unicode字符集的来说明的。 
1. Endian、位序、存储顺序、阅读顺序 
1) Endiian 
“Endian”一词来源于乔纳森•斯威夫特的小说格列佛游记。小说中,小人国为水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开而争论,争论的双方分别被称为Big-endians和Little-endians。 
Endian翻译为“字节序”,又称端序,尾序。在计算机科学领域中,字节序是指存放多字节数据的字节(byte)的顺序,典型的情况是整数在内存中的存放方式和网络传输的传输顺序。 
2) 位序(Endianness) 
位序可以用指位序(bit),位序是对于单字节数据来说的,对于单一的字节(byte),大部分处理器以相同的顺序处理位元(bit),因此单字节的存放方法和传输方式一般相同。大于一个字节的数据在内存中的存放顺序才会讨论字节顺序问题,一个字节的数据当然就无需谈顺序的问题。 
3) 存储顺序 
存储顺序是指存储在计算机内存中的地址顺序。例如,一个4字节整形数据0x0A0B0C0D,存储在CPU为intel的x86架构计算机的内存中,高字节数据(0x0A)存储在高地址,低字节数据(0x0D)存储在低地址。 
4) 阅读顺序 
阅读顺序就是人们习惯的看文字的顺序。还用“存储顺序”中的4字节整形数据来说明,0x0A0B0C0D为16进制表示形式,阅读顺序为从左到右(高字节到低字节)。在调试程序或编写程序经常看到或用到这样的常量,其实就是一个数据的表示形式,这个形式遵从人们的阅读习惯。 
2. Little Endian 与 Big Endian 
继续用上述4字节整形数据0x0A0B0C0D举例。从字面讲,Little Endian就是说小、端,即小数据(此处的小为阅读顺序中的低字节数据:0x0D)存储在前端(内存中的低地址),剩下3个字节的数据依次按照阅读顺序高字节的数据存储在内存中的高地址,如图1。Big Endian就是说大、端,即大数据(此处的大为阅读顺序中的高字节数据:0x0A)存储在前端(内存中的低地址),剩下3个字节的数据依次按照阅读顺序低字节的数据存储在内存中的高地址,如图2。 
地址:高 -> 低, 0A 0B 0C 0D 
图1 little endian 
地址:高 -> 低, 0D 0C 0B 0A 
图2 big endian 
3. 字节顺序在Unicode编码存储中的应用 
Unicode编码在不同的CPU架构的计算机中,存储采用Little Endian或Big Endian。例如:“汉”字的Unicode编码是0x6C49。如果在intel的x86架构的计算机中,将49存储在低地址,是little endian;在老式AMD系列的CPU(很老很老的那种,因为最新的AMD系列已经是x86架构了)架构的计算机中,,将6C存储在低地址,是big endian。 
4. 字节顺序在网络传输中的应用 
在大部分的开发中我们不需要考虑字节顺序的问题。唯有在跨平台以及网络程序应用中字节顺序才是一个应该被考虑的问题。 
1) 网络应用的字节顺序 
网络字节顺序是TCP/IP规定好的一种数据表示格式,它与具体的CPU类型、操作系统无关,从而可以保证数据在不同主机之间传输时能被正确解释。网络字节顺序采用big endian排序方式。在网络编程时,并不是什么时候都要考虑字节顺序问题。那么什么时候需要考虑呢? 
实际上如果是应用层的数据,即对TCP/IP来说是透明的数据,不用考虑字节顺序的问题。因为接收端收到的顺序是和发送端一致的。 
但对于TCP/IP关心的数据(IP地址、端口)来说就不一样了。例如我指定了一个端口号:unsigned short port = 0x0012 (十进制18),把这个端口号传个TCP/IP建立一个socket连接。 
sockaddr_in addr; 
addr.sin_family = AF_INET; //使用互联网际协议,即IP协议 
addr.sin_port = port; 
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); 
因为网络字节顺序是big endian,即低地址存放的是数值的高位,所以TCP/IP实际上把这个port解释为0x1200(十进制4608)。本来打算是要在端口18建立连接的,但TCP/IP协议栈却在端口4608建立了连接。 
当一个数据是应用层和TCP/IP都需要关心的时候,需要考虑这个数据的字节顺序(一般而言就是IP地址和端口号)。 
2) 字节顺序转换函数 
htons 把 unsigned short 类型从主机序转换到网络序 
htonl 把 unsigned long 类型从主机序转换到网络序 
ntohs 把 unsigned short 类型从网络序转换到主机序 
ntohl 把 unsigned long 类型从网络序转换到主机序 
这几个函数很好记,比如htons中hton代表host to network, s代表unsigned short 
char FAR * inet_ntoa( struct in_addr in); 
将一个IP转换成一个互联网标准点分格式的字符串。 
in_addr_t inet_addr(const char *cp); 
将一个点分十进制的IP转换成一个长整数型数(u_long类型)。返回值已是网络字节顺序,可以直接作为internet 地址。

猜你喜欢

转载自blog.csdn.net/weixin_41632560/article/details/81533535