最近又碰到了大小端引发的一些问题,看来是该来总结总结。

   大端方式将高位存放在低地址,小端方式将低位存放在高地址。采用大端方式 进行数据存放符合人类的正常思维,而采用小端方式进行数据存放利于计算机处理。但是也不是所有计算机都采用小端方式来存放数据。我们可以写个小程序来测试一下:

#include <stdio.h>
int main()
{
    int a = 0x1;
    if (*(char *)&a)
        printf("little mode\n");
    else
        printf("large mode\n");
    return 0;
}

对于上述示例,在32位系统中,0x1=0x00000001。不同模式下的存放方式如下:

地址偏移(B)0123
大端模式0x000x000x000x01
小端模式0x010x000x000x00


问题一:

   在网络编程中,ip地址都使用unsigned char类型数组存储,有些人习惯将ip地址转换成整型来比较(*(unsigned int *)ip1 == *(unsigned int *)ip2)。但是,我们不能像这样的来比较ip地址的大小。192.168.1.2与192.168.2.1来比较,很明显是192.168.2.1大。如果在小端模式的机器中,将他们转换成无符号整型的值分别为33663168和16951488,这样看来192.168.1.2反而比192.168.2.1大,很荒唐对吧?


问题二:

   还是在网络编程中,服务器端的部分应用程序会记录客户端的连接信息,依然来拿ip地址来说。当有大量的client连接,他们的ip信息都会使用hash链表来存储,相信大家都明白,如果用普通的链表那会增加查找的时间。hash的关键是算法,怎样避免冲突是重点。

   举例:hash桶深8192,散列算法是将ip地址转换为无符号整型再对桶深取模。

   也许第一眼看没什么问题,但想一想在小端模式下会是什么情况就能很快发现问题。很不巧,在同一个局域网中的ip地址前缀都相同。以192.168.0.0/16子网为例,小端模式下转换为无符号整型对8192取模,就像(168*256+192)%8192,也就是这整个子网中的ip都被散列到同一个hash桶里,ip地址的第3/4字节根本没有使用到。这与普通的链表存储好像没有区别哦。性能就别提了。

   修改一下散列算法,将ip前两字节与后两字节按位异或,再对桶深取模。效果就大不一样了,当然你可以设计其他更好的散列算法。


   这就是我最近碰到的大小端问题,如果大家还有其他类似问题,欢迎讨论交流。