字节序总结


1.数据存储的字节序与位序 

在各种计算机体系结构中,对于字节、字等的存储机制有所不同。对于同一个数 值,在不同的计算机体系中会以相反的顺序记录。例如,十六进制数值12345678H,在一 种计算机架构下存储为 12345678H,而在另一种计算机架构下会被存储为78563412H。这 就是按照不同的字节序进行存储的。所以所谓的字节序指的就是长度跨越多个字节的数据的存放形式。 

2. Endian的含义    

 目前的存储器,多以字节为访问的最小单元,当一个逻辑上的单元必须分割为物理上的若干单元时就存在了先放谁后放谁的问题。于是Endian的问题应运而生了。对于不同的存储方法,就有Big-endien和Little-endian两个描述。 Big-endian和Little-endian这两个术语来自于Jonathan Swift的《格利佛游记》。其中交战的两个派别无法就应该从哪一端—小端(Little-end)还是大端(Big-end)打开一个半熟的鸡蛋达成一致。支持从小端打开鸡蛋的一派被称为Little-endian,支持从大端打开鸡蛋的一派则被称为Big-endian. 在那个时代,Swift是在讽刺英国和法国之间的持续冲突。后来,一位网络协议的早期开创者Danny .Cohen,第一次使用这两个术语来指代字节顺序,后来这个术语被广泛接纳了。 

3. Little-endian的含义 

    Little-endian是一种小值的一端〔或序列中较不典型的值)存储在前的顺序,也就是说,最低字节存放在最低位,最高字节存放在最高位,反序排列。     依照人们的习惯来说,我们的文字及数字都是以从左到右的方式排列的,这似乎也被认为是自然的存储字符和数字方式。然而,Little-endian却恰恰与我们的习惯相反。例如,按照我们的习惯写一个十六进制数值56AB78EFH,把这个数值以Little-endian的方式表达出来,则是EF78AB56H。 1.2.3 Big-endian的含义 
    Big-endian是一种大值的一端(或序列中更典型值)存在前面(在最小的存储地址)的顺序,也就是最高字节在地址最低位,最低字节在地址最高位,依次排列。 
    Big-endian的方式与人们的书写习惯一致.例如,按照我们的习惯写一个十六进制数值56AB78EFH,把这个数值以Big-endian的方式表达出来,也是56AB78EFH。 1.2.4字节序与CPU架构的关系 

    谈到字节序的问题,必然涉及CPU的架构。CPU从架构上区分,有x86、x86-64、 IA-64等;从指令集上区分,有CISC, RISC等。     

1. CPU的架构   

  (1) x86架构 

    x86又称IA32,即Intel Architecture 32 (Intel 32位架构)。它是Intel为其第一块16位CPU( i8086)专门开发的。IBM 1981年推出的世界第一台微机中的CPU--i8088(i8086简化版)使用的也是x86架构。同时计算机中为提高浮点数据处理能力而增加了x87芯片,以后就将x86指令集和x87指令集统称为x86架构。 
    虽然随着CPL技术的不断发展,Intel陆续研制出更新型的i80386. i80486, Pentium系列及至强系列CPU,但为了保证计算机能继续运行以往开发的各类应用程序以保护和继承丰富的软件资源,所以Intel公司所生产的所有CPU仍然继续使用x86架构,所以它的CPU仍属于x86系列。由于Intel x86系列及其兼容CPU(如AMD等)都使用x86架构,所以就形成了今天庞大的x86系列及兼容CPU阵容。 

    目前基本上所有x86架构的CPU对数据的处理,都采用Little-endian字节序。    

 (2) x86-64架构 

    x86-64架构是由AMD公司设计的,也称为AMD 64。它可以在同一时间内处理64 位的整数运算,并兼容于x86-32架构。其中支持64位逻辑定址,同时提供转换为32位 定址选项;但数据操作指令默认为32位和8位,提供转换成64位和16位的选项;支持常规用途寄存器。如果是32位运算操作,就要将结果扩展成完整的64位。这样,指令中有“直接执行”和“转换执行”的区别.其指令字段是8位或32位,可以避免字段过长。 

x86-64架构的CPU对数据的处理,也采用Little-endian字节序。 

 (3) IA-64架构 

 IA-64架构是Intel为了全面提高以前IA-32处理器的运算性能,和HP公司共同开发了6年的64位CPU架构,是专为服务器市场开发的一种全新的处理器。它放弃了以前的x86架构,认为它严重阻碍了处理器的性能提高。 
IA-64架构的最初应用是英特尔的Itanium〔安腾)系列服务器处理器,后来的Itanium 2系列处理器也采用这一架构。由于它不能很好地解决与以前32位应用程序的兼容,所以应用受到较大的限制,尽管目前Intel采取了各种软、硬方法来弥补这一不足。但随着AMD x86-64架构处理器的全面投入,Intel的IA-64架构遭遇失败。 

IA-64架构的CPU对数据的处理,字节序是可配置的,既可以采用Little-endian.也可以采用Big-endian。

4.如何确定自己主机的字节序是大端字节序还是小端字节序? 
 
介绍:何为大端字节序和小端字节序? 
是在内存中存储字节的两种方式: 
大端字节序:高位值在内存中放低位地址; 
采用这种机制的处理器有IBM3700系列、PDP-10、Mortolora微处理器系列和绝大多数的RISC处理器。Motorola的PowerPC系列CPU采用big endian方式存储数据。 
 
小端字节序:低位值在内存中放低位地址。 
按照最低位字节(包含LSB的字节)至最高位字节(包含MSB的字节)的顺序,存放在连续的地址中。采用这种机制的处理器有PDP-11、VAX、Intel系列微处理器和一些网络通信设备。Intel的x86系列用little endian方式存储数据。 例外: 
目前在各种体系的计算机中,通常采用big-endian和little-endian两种字节存储机制描述在多字节数中各个字节的存储顺序。除了big-endian和little-endian之外的多字节存储顺序就是middle-endian。这种存储顺序偶尔会在一些小型机体系中的十进制数的压缩格式中出现。 
 方法一: 
一个主机是大端还是小端要看cpu类型以及运行在上面的操作系统。同一款cpu在不同的操作系统使用的大小端情况是不同的。当然我们通常使用的x86+windows是小端。 例子: 
1 Solaris[tm] OE (32-bit)              Big 

2 Solaris[tm] OE (64-bit)              Big 

3 HP-UX (64-bit)                         Big 

4 HP-UX IA (64-bit)                     Big 

5 HP Tru64 UNIX                          Little

6 AIX-Based Systems (64-bit)           Big 

7 Microsoft Windows IA (32-bit)        Little

8 Microsoft Windows IA (64-bit)        Little

9 IBM zSeries Based Linux               Big 

10 Linux IA (32-bit)                     Little 

11 Linux IA (64-bit)                     Little 

12 Microsoft Windows 64-bit for AMD    Little 

13 Linux 64-bit for AMD                  Little 

15 HP Open VMS                             Little 

16 Apple Mac OS                            Big 

17 Solaris Operating System (x86)       Little

18 IBM Power Based Linux                 Big 
  
方法二: 
通过程序查询可以了解自己的主机的字节序。 程序一: 
#include <iostream>   using namespace std;   
union    {    int number;    char s;   }test;  
bool testBigEndin()   {    test.number=0x01000002;    return (test.s==0x01); }   
void main()   {    if (testBigEndin())       cout<<"big"<<endl;    else     cout<<"small"<<endl; }  
在vc++6.0环境下,编译运行可以得出运行结果,即:得出本机的字节序类型。   

方法三: 
一个字节8位刚好存储两个十六进制的数字。网络字节序即为大头字节序。判断当前平台是大头还是小头: 
#define BIGENDIAN (htons(1) == 1) 
当htons(1) == 1成立时,BIGENDIAN的值就是1,否则为0. 后续代码就可以通过 if (BIGENDIAN) { ……}的形式来判断大小头。  
各操作系统都会实现这个函数: unit16_t htons(uint16_t host);  
将16位主机字符顺序转换成网络字符顺序 
如果主机字节序是小头,则返回十进制host对应的大头;
如果主机字节序是大头,则返回十进制host对应的大头(即不需要转换,本身就是大头). 主机的字节序是大头还是小头由htons自己去确定。 
假设主机为小头字节序,那么十进制数字1(十六进制数字就是0x0001)的主机字节序就是: 0X0100 
用htons将0X0100按小头字节序转换为网络字节序(大头)是: 0X0001 
即传入参数host为0X0100,返回值就是0X0001。 
而因为程序是在当前平台上执行,所以cpu在读取16为short时都是按照本级的字节序小头来读的。 
cpu是不知道你返回的值是大头字节序的,它只知道都按本机的小头字节序来读取。 所以传入值为0X0100,即十进制的1;而返回值为0X0001,即256. 转换字节序后,本机cpu读取出来的short的值是不同的。 
 假设主机是大头,那么十进制数字1(十六进制数字就是0x0001)的主机字节序就是: 0X0001 
htons不用转换,直接返回,因为本身就是网络字节序: 0X0001 
即传入参数host为0X0001,返回值也是0X0001。 cpu都会按本机的字节序去读取传入值和返回值: 
传入值为0X0001,即十进制的1;而返回值为0X0001,十进制值就是1. 所以如果本机是大头,则htons(1) == 1 成立;否则不成立。

猜你喜欢

转载自blog.csdn.net/qinglongzhan/article/details/78609287