大小端问题

来源:互联网 发布:刷逆战nz点软件 编辑:程序博客网 时间:2024/06/07 15:52

最近公司结构调整,工作的变动让我开始审视自己,才恍然发现自己已经长时间处于舒适区了,感觉就像一条温水的青蛙,慢慢被生活煮着。看起来整日忙忙碌碌,工作越发熟悉,工作内容挺饱满,但实际知识掌握得却很肤浅,根本谈不上精通。有感于此,我决定要将工作这几年学到的知识系统梳理一下,用笔讲清楚,这才谈得上是掌握。

首先把最近遇到的一些大小端问题拿出来,也算练一下文笔。


什么是大小端?
大小端指的是数据保存的两种字节序。
大端(Big endian)指数据的高字节保存在内存的低地址处,数据的低字节保存在内存的高地址处。
小端(Little endian)正好相反,数据的高字节保存在内存的高地址处,数据的低字节保存在内存的低地址处。

比如0x12345678,大端模式的存放方式如下:
字节 0x 12 34 56 78
地址 0x 0043 0044 0045 0046 低地址 – > 高地址

而小端模式的存放方式如下:
字节 0x 78 56 34 12
地址 0x 0043 0044 0045 0046 低地址 – > 高地址

网络字节序和主机字节序
网络字节序是TCP/IP规定好的一种数据表示格式,与具体的CPU类型,操作系统无关,从而可以保证数据在不同主机间传输时能被正确理解。网络字节序采用大端模式。
主机字节序与客户主机采用的CPU类型有关,一般而言x86芯片采用小端,ARM多采用小端,而MIPS多采用大端。

网络字节序与主机字节序之间可以通过通用函数转换
htons: unsigned short类型从主机字节序转成网络字节序
htonl : unsigned long类型从主机字机序转成网络字节序
ntohs: unsigned short类型从网络字节序转成主机字节序
ntohl: unsigned long类型从网络字节序转成主机字节序

问题汇总
大小端错误问题大体分为两种,一种是未进行大小端转换,这是比较常见的,多出现在解析网络数据包,以及构建socket的情况下。网络数据包均为大端,若主机字节序为小端,在未进行字节序转换的情况下可能出现指针越界的情况,举个例子,数据包某层协议存在长度字段,占两个字节,若不对长度数据进行大小端转换,则获取的数值是完全错误的,使用这个数值移动指针,指针溢出的可能性极大。另外创建socket时addr,port字段均必须为网络字节序。

另一种情况就是重复进行大小端转换,这种情况出现的概率也很大,原因多是对使用的系统函数不熟悉,系统函数已经对数据进行了转换,但函数外面又进行了一次转换,导致重复大小端转换,相当于没有转换。举个例子,in_addr_t inet_addr(const char *cp)函数解释为converts the Internet host address cp from IPv4-number-and-dots notation into binary data in network byte order, 可以看出函数返回值即为网络字节序,这时不能再调用如htonl等函数了。

不尽之处恳请提出,谢谢。