当一个数据单元是由多个字节组成的时候,存储和传输都要面对字节序的问题,这是为什么呢?
简单一点,一个 短整型的数据 0x1234 由两个字节组成,而且通常意义下,我们会将0x12称为高字节,0x34称为低字节部分。问题很明显,当存储这个数据和在网路上传输这个数据的时候就有问题了,首先说存储,因为存储的时候是一个字节一个字节存储的吗(就是说内存的存储单元是字节,而且是从低字节到高字节),所以是先存储这个数据的高字节部分呢还是低字节部分呢?然后是传输,当网络协议将这个数据在网络上传输的时候是先传输这个数据的高字节部分还是低字节部分呢?其实这个问题只是一个选择问题,选择那一个存储方式似乎都可以,很早的时候那些CPU产商也是这么认为的,所以PowerPC,Motor他们选择了先存储高字节部分,也就是说在内存中数据可能是这样子(地址低-》高) 1234,这似乎符合常规思维,因为我们书写一个多字节数据的时候会先写高字节部分。而Intel x86系列的CPU采用的是小端,也就是先存储多字节数据的低字节部分(所谓的先存储前面说了,就是存储在低地址那里),其实不同的CPU产商选择不同的字节序在以前是没有问题的,因为那时电脑之间基本没有什么交互,非常独立,而且关键是软件也是特别配置的,PC和软件是捆绑在一起的,所以说各CPU想我想选择什么字节序就选择什么字节序,反正对客户是透明的。伴随着软件的商业化并进行独立销售,以及网络时代的到来,麻烦就来了,大概来说会有两个麻烦:
(1)软件移植问题,夸平台需求高涨。
对于向C/C++这种纯编译语言,他们产生的可执行代码是针对具体CPU的,所以不同平台上编译的C/C++代码不能互通,举个非常浅显的例子,在x86平台下编写的一个程序在内存中保存了上面那个数据 0x1234,在内存中的情况就会是 3412,而这时用PowerPC编写的一个程序必须和这个程序产生的结果交互,所以需要读取这个数据,如果不做处理的话,他读出来后会理解成0x3412,因为它理解是 在低地址处的0x34是高字节部分。当然C/C++程序的平台相关性不只是CPU的字节序导致的,只是说明当时字节序的一个不统一为这种类似问题带来不少麻烦,但是这种问题并没有解决,也就是说各家CPU的字节序还是不同的,其实这个问题在移植说法上有点点牵强,因为C/C++代码要在其他平台上运行的话是免不了重编的,所以这个字节序的问题也就不是什么大问题,关键是下面说的那个麻烦,网络传输。
(2)网络传输问题。
比较好的是,网络协议统一在传输一个多字节数据的时候会先传输其高字节部分,其实这个意思是说网络在传输的时候会将内存中的一个多字节数据理解成大端数据,也就是会将高字节部分先传输然后是低字节。这里麻烦就来了 网络传输一个数据的时候,(数据当然在内存中)怎么知道哪部分是高字节,哪一部分是低字节,如果程序中不显示告诉他,他当然就会认为低地址那里的数据是高字节了,因为网络是大端的。这种情况下,若本地CPU是大端的话就躲过一劫了,当然对方肯定不会有问题的,因为对方肯定知道网络上传来的数据是大端的(这就是统一规定的好处)所以对方会将先到的数据当成高字节部分。但是若是本地CPU是小端的话,那么网络先传的就是 0x34了,然后是0x12,而对方受到之后会理解成0x3412,因为他坚信网络是大端的,他是没错的。所以我们在传输数据的时候不管怎么样必须做字节序转换不要赌自己的机子是大端的,市面上有CPU是可以配置大小端的如MIPS处理器。ANSI C提供了四个库函数来作网络字节序和本地主机字节序的转换问题。
就说到这里了,字节序问题主要是在网络编程的时候要注意。