测试本机的大小端模式

来源:互联网 发布:php 参数传递 编辑:程序博客网 时间:2024/06/05 15:33

1. 什么是大小端模式?区别?  (小端存储模式和大端存储模式)

   如数字0x1234,低字节位是0x34,高字节位是0x12。 假设从地址0x4000处开始存放

     内存地址         小端模式(little-endian)       大端模式(big-endian)

      0x4000           0x34                                  0x12

      0x4001           0x12                                  0x34


总:Little-Endian,数据类型中的高位数据存放于高地址部分,底位数据存放于底地址部分。

       Big-Endina, 数据类型中的高位数据存放于内存的地址部分,低位数据存放于内存的低地址部分!


      采用Little-endian模式的CPU对操作数的存放方式是从低字节到高字节,

      而Big-endian模式对操作数的存放方式是从高字节到低字节。


        计算机世界中借用大小端指“多字节数据类型中的字节顺序”。


注:不管是大端还是小端,cpu总是从内存的低位到高位读取数据

      每一个内存单元都是8位,对应1字节!


2. 各自的优缺点?

    没有谁优谁劣之分,各自的优势便是对方的劣势!

   大端模式:符号位在第一字节,容易判断正负!

    小端模式:???


3. 大小端之分产生的原因?

     大小端模式是字节序不同......(待补充)

     计算机世界中借用大小端指“多字节数据类型中的字节顺序”。


4. 数组在大小端模式下的存储

以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,

我们可以用unsigned char buf[4]来表示value:
  Big-Endian: 低地址存放高位,如下:         Little-Endian: 低地址存放低位,如下:
高地址
        ---------------
        buf[3] (0x78) -- 低位                                   buf[3] (0x12) -- 高位
        buf[2] (0x56)                                               buf[2] (0x34)
        buf[1] (0x34)                                               buf[2] (0x34)
        buf[0] (0x12) -- 高位                                   buf[0] (0x78) -- 低位
低地址---------------


5. 大小端模式的具体应用

比如某协议规定了数据按大端模式(Big-Endian)组织,而实现协议的系统是小端模式(Little-Endian), 那么协议的实现代码就需要对输入数据从(Big-Endian)转换为(Little-Endian),再进行运算, 输出数据也要从(Little-Endian)转换为(Big-Endian)。

在网络上传输数据时,由于数据传输的两端可能对应不同的硬件平台,采用的存储字节顺序也可能不一致,因此 TCP/IP 协议规定了在网络上必须采用网络字节顺序(也就是大端模式) 。 
通过对大小端的存储原理分析可发现,对于 char 型数据,由于其只占一个字节,所以不存在这个问题,这也是一般情况下把数据缓冲区定义成 char 类型 的原因之一。对于 IP 地址、端口号等非 char 型数据,必须在数据发送到网络上之前将其转换成大端模式,在接收到数据之后再将其转换成符合接收端主机的存储模式。

Linux 系统为大小端模式的转换提供了 4 个函数,输入 man byteorder 命令可得函数原型
htonl 表示 host to network long ,用于将主机 unsigned int 型数据转换成网络字节顺序; 
htons 表示 host to network short ,用于将主机 unsigned short 型数据转换成网络字节顺序; 
ntohl、ntohs 的功能分别与 htonl、htons 相反



6. 判断本机大小端模式的方法

  思路1:如一个unsigned int a = 0x 1234; 把a转换成unsigned char (单字节),unsigned char *b = (unsigned char *)&a;

             因为b(字符串首地址,第一个地址)表示整个字符串,所以只需判断b[0] 是否等于0x34就知是否是小端模式!

#define U16 unsigned short;#define U8  unsigned char;int IsLittleEndian(){U16   i = 0x1234;U8*   p = (U8*)&i;if( p[0] == 0x34 && p[1] == 0x12 )return 1;//系统是Little-Endianif( p[0] == 0x12 && p[1] == 0x34 )return 0;//系统是Big-Endianreturn 0;}



方法2:读写联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性,可轻松地获得CPU对内存采用Little-endian还是Big-endian模式

typedef enum {false, true} bool;bool IsBigEndian(){union NUM{int a;char b;}num;              num.a = 0x1234;           if( num.b == 0x12 )        return true;return false;        //return (num.b == 0x12);}

7. 大小端模式之间的转换!

(待补充)


8.常见的字节序

 一般操作系统都是小端,而通讯协议是大端的。

8.1 常见CPU的字节序
Big Endian : PowerPC、IBM、Sun
Little Endian : x86、DEC
ARM既可以工作在大端模式,也可以工作在小端模式。

8.2 常见文件的字节序
Adobe PS – Big Endian
BMP – Little Endian
GIF – Little Endian
JPEG – Big Endian

Java和所有的网络通讯协议都是使用Big-Endian的编码。



补:十六进制数,以0x开始,这里的0是数字0,不是字母O!       

      我们为什么常用十六进制数呢?计算机中所有的数据都是以二进制的形式存储的,有时用二进制我们可以直观的解决问题。

 但是二进制表示数太长,如int a = 3; 用二进制表示 0000000  00000000 00000000  00000011 面对这么长的数进行思考或操作,没有人会喜欢。

 因此,C,C++ 没有提供在代码直接写二进制数的方法。用16进制或8进制可以解决这个问题。