zoukankan      html  css  js  c++  java
  • 大小端 Big-Endian 与 Little-Endian

    应该说没做底层开发(硬件或驱动)的人很可能不会彻底理解大小端的概念,大小端不是简单的一句“大端在前”还是“小端在前”能够概括的问题。在cpu, 内存, 操作系统, 编译选项, 文件,网络传输中均有大小端的概念,这些东西加在一起,就很容易把人搞晕。我自己就晕过很久。

    为方便说明,再做一些定义:

    (1) 内存

    可以存储若干个单元数据的物理设备,每个单元存储1个字节,每个单元有一个地址,其地址线程增长。为方便说明,假设内存地址从 0000:0000 一直增加到FFFF:FFFF。

    用一个带箭头的直线表示地址的增长方向,例如

    -------------------------->

    表示左边的数据处于低地址,右边的数据处于高地址。

    (2) U32整型

    对于unsigned int的变量,计算机是以32bits存储的,即连续的4个字节。比如说,对一个值为0x11223344的整数,在内存中的排列方式可能为:

    -------------------------->

    11  22  33  44 (大端)

    也可能为

    44  33  22  11 (小端)

    从CPU说起

         在有了上述定义之后,开始讲大小端的起源。这得从CPU说起,我们知道CPU要从内存中加载程序数据来运行,CPU要对数字进行运算。那么,CPU在从内存加载4个字节的数据之后,要把它作为一个数字来运算。那它是怎么看待这个数字的呢?

    -------------------------->

    11  22  33  44

        有的CPU认为它是0x11223344,有的CPU认为它是0x44332211。所以CPU就分为两类:Big-Endian和Little-Endian, 认为它是0x11223344的就是Big-Endian,认为它是0x44332211的就是Little-Endian。

        有人会为,CPU的“认为”是什么意思。这其实物理上的电路问题,CPU的所有运算都是通过电路完成,其连接逻辑已经决定了它是按大端运算还是按小端运算。

    程序

         在知道了CPU的大小端之后,我们要写一个程序让CPU来运行,那么显然,程序必须遵从CPU的大小端。程序最终会load到内存里,所以其大小端的定义要和CPU一致。

         具体得,程序都是有很多条指令构成的,每条指令4个字节。假设程序里有一个指令ADD,机器码为0xAABBCCDD。显然,只有内存里按顺序AABBCCDD出现时,CPU才能理解为是ADD。不然CPU根据不能辨识这条指令。

    文件

        程序是放在哪的呢?放在文件里的,文件也是线性的。所以可以这么认为,文件就是内存的一份映像,其数据内容是完全一样的(实际上不一样,但可以这么理解)。所以,如果cpu是大端,那么内存中的程序也必须是大端,保存程序的文件也必须是大端。

    程序的编译

        程序从哪来的?编译器编出来的。我们在用gcc来编译一个程序时,可能没有发现任何关于Endian的参数设置。这是因为有一个默认选项被指定义了。这可以参考gcc/ld相关的文档,关于link script的描述。在link script里是可以指定endian的。

      从上面可以看出,cpu、程序、编译过程这一套东西,其大小端都必须是一致的。这里就简称为系统的大小端。

    网络传输

         网络传输数据时需要考虑大小端。例如,想发送一个U32的数字给对方,需要连续发送4个字节。那么是才发送高字节,还是先发送低字节呢?一般来说,网络上一般是先传送高字节,即大端,又称为网络字节序。例如,在传递0x12345678的时候,会先传0x12, 再传0x34, 再0x56, 再0x78。

    在代码判断大小端

    inline bool IsLittleEndian()
    {
        unsigned int a = 0x01;
        return (*((unsigned char*)&a) == 1);
    }

    系统无关的写法

    在传送和保存数据时,可以写一份不管系统是大端还是小端、结果都相同的代码。这是用移位来实现的。比如,我们从网络上接收到4个字节,想把它转成一个U32。

    U8 buf[4]; // 接收到4个字节, 按大端传递

    U32 v = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];

    一种错误的写法

    在做编解码的时候会经常遇到关于大小端的问题,而写错的人大有人在,协议定义不好的也大有人在。一般来说,只要发现一个协议把数据定义成小端,那么我一般猜到了作者想干什么了。例如, 定义一个协议,发送以下数据,以小端发送。

    U8  a

    U8  b

    U16  c

    U32  d

    那么程序基本上会这么写代码:

    struct Msg

    {

        U8 a;

        U8 b;

        U16 c;

        U32 d;

    };

    U8 buf[8];

    Msg msg;

    memcpy(&msg, buf, 8);

    那intel的机器上,会发现这样刚好是对的。但是我要说这是不正确的写法。

    BIT有大小端吗?

    在软件编程领域,大小端总是按BYTE计算的,永远无需考虑BIT的大小端。因为数据的最小单元是BYTE,在物理环节中其顺序都固定好了,永远对的上。正因为如此,我们可以用位域来接收按位定义的信息,而不必担心大小端。如在PES的头部:

    struct Flags

    {

      TS_UINT8 original_or_copy : 1;
      TS_UINT8 copyright : 1;
      TS_UINT8 alignment_indicator : 1;
      TS_UINT8 priority : 1;
      TS_UINT8 scrambling_control : 2;
      TS_UINT8 not_used : 2;

    }

    但要注意的是,这仅限于字节之内的情形。

     
    转载链接:http://blog.csdn.net/xiaojun111111/article/details/42294223
    其他相关链接: 

    ENDIAN的由来及BIG-EDIAN 和LITTLE-ENDIAN

    一、引子   在各种计算机体系结构中,对于字节、字等的存储机制有所不同,因而引发了 计算机通信领域中一个很重要的问题,即通信双方交流的信息单元(比特、字节、 字、双字等等)应该以什么样的顺序进行

    字节顺序:高位优先(big-endian)和低位优先(little-endian)

    字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处;大端字节序是高字节数据存放在低地址处
  • 相关阅读:
    use paramiko to connect remote server and execute command
    protect golang source code
    adjust jedi vim to python2 and python3
    install vim plugin local file offline
    add swap file if you only have 1G RAM
    datatables hyperlink in td
    django rest framework custom json format
    【JAVA基础】网络编程
    【JAVA基础】多线程
    【JAVA基础】String类的概述和使用
  • 原文地址:https://www.cnblogs.com/1175429393wljblog/p/8175931.html
Copyright © 2011-2022 走看看