一、大端字节序 vs. 小端字节序
字节序指一个多字节对象在内存中存储的方式,小端字节序机器在存储多字节对象时采用低地址存低有效字节的策略,大端则恰恰相反。字节序由CPU架构决定,与操作系统无直接关系。像常见的x86架构、arm架构CPU,都采用的是小端字节序,而power pc采用的是大端字节序。
举个栗子:
变量x的类型为int,位于地址0x100处,它的十六进制值为0x01234567.那么内存中的映像如下表所示:
地址 | 0x100 | 0x101 | 0x102 | 0x103 |
大端法-值 | 01 | 23 | 45 | 67 |
小端法-值 | 67 | 45 | 23 | 01 |
二、如何判断机器的字节序
现在很多CPU架构已经同时支持大端字节序与小端字节序,就我自己实际情况而言,很少遇到大端机器。或许你在面试的过程中有被问到用编程的方式判断当前机器字节序的问题,内核代码中就有很好的示范:
static union { char c[4]; unsigned long mylong; } endian_test = { {'l', '?', '?', 'b'} };
#define ENDIANNESS ( (char)endian_test.mylong )
宏ENDIANNESS输出l就是小端机器,输出b就是大端机器。
三、socket编程中的大小端
学过socket编程的都知道,在发送数据前需要使用hton这样的函数进行主机字节序到网络字节序的转换。那么是不是所有的数据都需要这样的转换呢?显然不是。
因为在网络中传输的数据就是单纯的字节流,假设现在有A主机给B主机通过网络发送数据,B不能知道A是大端机器还是小端机器,自然也不能知道接受到的数据是大端字节序还是小端字节序。因此,必须约定发送到网络中的数据的字节序(大端字节序)。A在发送数据前调用hton做字节序转换,如果A本身是大端机器(主机序是大端序),那么hton就是一个空操作。如果A是小端机器(主机序是小端序),那么hton就完成了小端序到大端序的转换(主机序到网络序的转换)。这样,B从网络拿到数据就按照约定的大端序(网络序)做处理。
这过程有一个有趣的事实是,数据(或字节流)从A发送到B,在内存中的存储顺序并不会发生任何改变。B在收到数据后,如果是单字节的对象(如char类型,字符串也是一样),不存在字节序的问题。如果是多字节的对象(如int类型),那么就调用ntoh做网络序到主机序的转换。如果B是大端机器(主机序本身是大端序),那么ntoh就是一个空操作,反之,ntoh就完成大端序到小端序的转换(网络序到主机序的转换)。
四、总结
如果是本地存储,对于一个多字节对象,大端与小端机器在内存中的映像是完全相反的。
如果是通过网络发送,发方在发送前,要将多字节对象做主机序到网络序的转换。收方收到的数据(或字节流)在内存中的映像与发方是完全一致的,只是在处理多字节对象时,需要做网络序到主机序的转换。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)