精华内容
下载资源
问答
  • 小端模式
    千次阅读
    2019-05-25 16:32:52

         大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。

         小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

    中文名外文名
    大小端模式Big-endian/Little-endian

    简明区分

         下面以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value

         Big-Endian: 低地址存放高位,如下:

         高地址
      ---------------
      buf[3] (0x78) -- 低位
      buf[2] (0x56)
      buf[1] (0x34)
      buf[0] (0x12) -- 高位
      ---------------
      低地址

         Little-Endian: 低地址存放低位,如下:

         高地址
      ---------------
      buf[3] (0x12) -- 高位
      buf[2] (0x34)
      buf[1] (0x56)
      buf[0] (0x78) -- 低位
      --------------

         低地址

    内存地址小端模式存放内容大端模式存放内容
    0x40000x780x12
    0x40010x560x34
    0x40020x340x56
    0x40030x120x78

    名词解析

    大端模式

         所谓的大端模式(Big-endian),是指数据的高字节,保存在内存的低地址中,而数据的低字节,保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;

         例子:

         0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000

         0000440: b484 6c4e 004e ed00 0000 0000 0100 0000

         在大端模式下,前32位应该这样读: e6 84 6c 4e ( 假设int占4个字节)

    小端模式

         所谓的小端模式(Little-endian),是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

         例子:

         0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000

         0000440: b484 6c4e 004e ed00 0000 0000 0100 0000

         在小端模式下,前32位应该这样读: 4e 6c 84 e6( 假设int占4个字节)

    大小端模式

          为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题,因此就导致了大端存储模式和小端存储模式。

          例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。

          我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以随时在程序中(在ARM Cortex 系列使用REV、REV16、REVSH指令)进行大小端的切换。

          下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:

    short int x;
    char x0,x1;
    x = 0x1122;
    x0 = ((char*)&x)[0]; //低地址单元
    x1 = ((char*)&x)[1]; //高地址单元

         若 x0 = 0x11,则是大端; 若 x0 = 0x22,则是小端......

         从上面的程序还可以看出,数据寻址时,用的是低位字节的地址。

    简单大小端转换的宏

    #define sw16(x)
     ((short)(
      (((short)(x)&(short)0x00ffU)<<8)|
      (((short)(x)&(short)0xff00U)>>8)))

    现阶段状况

          目前Intel的80x86系列芯片是唯一还在坚持使用小端的芯片,ARM芯片默认采用小端,但可以切换为大端;而MIPS等芯片要么采用全部大端的方式储存,要么提供选项支持大端——可以在大小端之间切换。另外,对于大小端的处理也和编译器的实现有关,在C语言中,默认是小端(但在一些对于单片机的实现中却是基于大端,比如Keil 51C),Java是平台无关的,默认是大端。在网络上传输数据普遍采用的都是大端。

    更多相关内容
  • 但是,大多数情况下,数据不是按照单字节的方式存储的,例如会有类似于int,double等数据类型,这就涉及到存储顺序的问题了,于是也就出现了两种存储方:大端模式(big endian)和小端模式(little endian)。

    1. 为什么会有大端模式和小端模式

    在计算机中,我们知道数据是按照字节存储的,如果数据都是单字节存储,就不涉及存储顺序的问题。但是,大多数情况下,数据不是按照单字节的方式存储的,例如会有类似于int,double等数据类型,这就涉及到存储顺序的问题了,于是也就出现了两种存储方:大端模式(big endian)和小端模式(little endian)

    我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。

    2. 大端模式与小端模式的存储方式

    • 大端模式(顺序):高字节在前(高字节存放在地址的低端),低字节在后
    • 小端模式:高字节在后,低字节在前
    • 大端模式的优点:符号位的判定固定为第一个字节,容易判断正负
    • 小端模式的优点:强制转换数据不需要调整字节内容

    2.1 举例说明一

    以0x1234为例进行说明。

    地址0x4000(低地址)0x4001(高地址)
    大端存储0x120x34
    小端存储0x340x12

    2.2 举例说明二

    下面来看看数组在大端模式和小端模式的存储区别,以unsigned int value = 0x12345678进行说明,假设有unsigned char buf[4]的一个数组。

    • 大端模式

    buf[3] (0x78) – 高地址,存放低位(字节)
    buf[2] (0x56)
    buf[1] (0x34)
    buf[0] (0x12) – 低地址,存放高位(字节)

    低地址 -----------------> 高地址
    0x12 | 0x34 | 0x56 | 0x78

    • 小端模式

    buf[3] (0x12) – 高地址,存放高位(字节)
    buf[2] (0x34)
    buf[1] (0x56)
    buf[0] (0x78) – 低地址,存放低位(字节)

    低地址 ------------------> 高地址
    0x78 | 0x56 | 0x34 | 0x12

    可见,大端模式和字符串的存储模式类似。

    3. 用代码判断大端和小端

    3.1 union判断

    使用union类型共享内存的判断方法。联合体union的存放顺序是所有成员都从低地址开始存放

    bool IsBigEndian()
    {
        union
        {
            unsigned short a ;//2个字节
            char b ;//高地址
        } c;
    
        c.a =0x0102 ;
    
        if(c.b ==1)//如果高地址存放低字节
            return true ;
        else
            return false ;
    }
    

    3.2 int判断法

    直接取int类型的高地址

    bool IsBigEndian()
    {
        int a =1 ; 
        if(((char*)&a)[3] ==1)//直接取高地址
            return true ;
        else
            return false ;
    }
    

    4. Intel格式与Motorola格式

    在进行CAN总线通信设计或者测试过程中,经常看到CAN总线信号的编码格式有两种定义:Intel格式与Motorola格式。Motorola是大端字节序,Intel是小端字节序

    4.1 CAN报文

    CAN总线上有4种报文:数据帧、远程帧、错误帧、超载帧。其中只有数据帧真正承载数据。假设报文中含有8各字节的数据,共8*8 = 64 bit

    • 如果位编号从右至左(R2L),那么:
     7   6   5   4   3   2   1   0
    --------------------------------
                                    | 0
                                    | 1
                                    | 2
                                    | 3
                                    | 4
                                    | 5
                                    | 6
                                    | 7
    
    • 如果位编号从左至右(L2R),那么:
     0   1   2   3   4   5   6   7
    --------------------------------
                                    | 0
                                    | 1
                                    | 2
                                    | 3
                                    | 4
                                    | 5
                                    | 6
                                    | 7
    

    这两种编号方式中,字节的编号是一样的,位的编号不同。CAN报文是串行发送的,CAN节点在发送报文时,不论如何编号,总是从表的左上第一位开始发送。从左至右,从上至下

    4.2 Intel格式与Motorola格式排列

    使用<或者>表示信号的衔接点。

    • Intel格式

    Intel格式的信号的每位,从MSB(高字节)到LSB(低字节),按照从右至左,从上至下的顺序排列(向右上角塞)

     x   x   x   x   x   x   x   x
    --------------------------------
    >.. ... ... ... ... ... ... MSB | 0
                    LSB ... ... ..> | 1
                                    | 2
                                    | 3
                                    | 4
                                    | 5
                                    | 6
                                    | 7
    
    • Motorola格式

    而Motorola格式的信号,从MSB(高字节)到LSB(低字节),按照每位从左至右,从上至下排列(向左上角塞)

     x   x   x   x   x   x   x   x
    --------------------------------
    MSB ... ... ... ... ... ... ..< | 0
    <.. ... ... LSB                 | 1
                                    | 2
                                    | 3
                                    | 4
                                    | 5
                                    | 6
                                    | 7
    

    从上面可以看出,Motorola格式对can报文的解析更加友好。

    5. 大端数据解析示例

    在这里插入图片描述
    解析方法:
    在这里插入图片描述
    以速度为例,如果速度为负值,需要对speed或0xF800,因为要取反+1,对不需要的数据补上1,防止对要解析的数据造成影响。如果是满字节,不管正数还是负数,也就无所谓补1了

    //目标信息结构体
    typedef struct
    {
        uint64_t snr      :  8;  //SNR
        uint64_t dynProp  :  3;  //运动状态
        uint64_t resv     :  2;
        uint64_t latVel   :  9;  //横向速度
        uint64_t angle    : 10;  //角度
        uint64_t velocity : 11;  //速度
        uint64_t range    : 13;  //距离
        uint64_t objId    :  8;  //目标ID
    }stObjInfoMsg;
    
    //buf为待解析的8个字节
    uint8_t * ptr = (uint8_t *)(buf);
      uint64_t msgdata = ((uint64_t)ptr[0] << 56) | ((uint64_t)ptr[1]   << 48)
                        | ((uint64_t)ptr[2] << 40) | ((uint64_t)ptr[3]   << 32)
                        | ((uint64_t)ptr[4] << 24) | ((uint64_t)ptr[5]   << 16)
                        | ((uint64_t)ptr[6] << 8)  | ((uint64_t)ptr[7]   << 0);
      stObjInfoMsg *pMsg = (stObjInfoMsg *)&msgdata;
    
      m_ID = pMsg->objId;
      m_Range = (float)pMsg->range / 5;
      m_Speed = pMsg->velocity & 0x400 ? (float)((int16_t)(pMsg->velocity | 0xF800)) / 5
                                                  : (float)((int16_t)(pMsg->velocity & 0x3FF)) / 5;
      m_Angle = pMsg->angle & 0x200 ? (float)((int16_t)(pMsg->angle | 0xFC00)) / 4
                                              : (float)((int16_t)(pMsg->angle & 0x1FF)) / 4;
    
    展开全文
  • 详解大端模式和小端模式

    千次阅读 2021-06-04 04:12:41
    如果从实际应用的角度说,采用小端模式的处理器需要在软件中处理端模式的转换,因为采用小端模式的处理器在与小端外设互连时,不需要任何转换。而采用大端模式的处理器需要在硬件设计时处理端模式的转换。大端模式...

    七、如何进行转换

    对于字数据(16位):

    #define BigtoLittle16(A)  (( ((uint16)(A) & 0xff00) >> 8)    | \

    (( (uint16)(A) & 0x00ff) << 8))

    对于双字数据(32位):

    #define BigtoLittle32(A)  ((( (uint32)(A) & 0xff000000) >> 24) | \

    (( (uint32)(A) & 0x00ff0000) >> 8)  | \

    (( (uint32)(A) & 0x0000ff00) << 8)  | \

    (( (uint32)(A) & 0x000000ff) << 24))

    八、从软件的角度理解端模式

    从软件的角度上,不同端模式的处理器进行数据传递时必须要考虑端模式的不同。如进行网络数据传递时,必须要考虑端模式的转换。在Socket接口编程中,以下几个函数用于大小端字节序的转换。

    #define ntohs(n)    //16位数据类型网络字节顺序到主机字节顺序的转换

    #define htons(n)    //16位数据类型主机字节顺序到网络字节顺序的转换

    #define ntohl(n)      //32位数据类型网络字节顺序到主机字节顺序的转换

    #define htonl(n)      //32位数据类型主机字节顺序到网络字节顺序的转换

    其中互联网使用的网络字节顺序采用大端模式进行编址,而主机字节顺序根据处理器的不同而不同,如PowerPC处理器使用大端模式,而Pentuim处理器使用小端模式。

    大端模式处理器的字节序到网络字节序不需要转换,此时ntohs(n)=n,ntohl = n;而小端模式处理器的字节序到网络字节必须要进行转换,此时ntohs(n) = __swab16(n),ntohl = __swab32(n)。__swab16与__swab32函数定义如下所示。

    #define ___swab16(x)

    {

    __u16 __x = (x);

    ((__u16)(

    (((__u16)(__x) & (__u16)0x00ffU) << 8) |

    (((__u16)(__x) & (__u16)0xff00U) >> 8) ));

    }

    #define ___swab32(x)

    {

    __u32 __x = (x);

    ((__u32)(

    (((__u32)(__x) & (__u32)0x000000ffUL) << 24) |

    (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) |

    (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) |

    (((__u32)(__x) & (__u32)0xff000000UL) >> 24) ));

    }

    PowerPC处理器提供了lwbrx,lhbrx,stwbrx,sthbrx四条指令用于处理字节序的转换以优化__swab16和__swap32这类函数。此外PowerPC处理器中的rlwimi指令也可以用来实现__swab16和__swap32这类函数。

    在对普通文件进行处理也需要考虑端模式问题。在大端模式的处理器下对文件的32,16位读写操作所得到的结果与小端模式的处理器不同。单纯从软件的角度理解上远远不能真正理解大小端模式的区别。事实上,真正的理解大小端模式的区别,必须要从系统的角度,从指令集,寄存器和数据总线上深入理解,大小端模式的区别。

    九、从系统的角度理解端模式

    先补充两个关键词,MSB和LSB:

    MSB:MoST Significant Bit ------- 最高有效位

    LSB:Least Significant Bit ------- 最低有效位

    处理器在硬件上由于端模式问题在设计中有所不同。从系统的角度上看,端模式问题对软件和硬件的设计带来了不同的影响,当一个处理器系统中大小端模式同时存在时,必须要对这些不同端模式的访问进行特殊的处理。

    PowerPC处理器主导网络市场,可以说绝大多数的通信设备都使用PowerPC处理器进行协议处理和其他控制信息的处理,这也可能也是在网络上的绝大多数协议都采用大端编址方式的原因。因此在有关网络协议的软件设计中,使用小端方式的处理器需要在软件中处理端模式的转变。而Pentium主导个人机市场,因此多数用于个人机的外设都采用小端模式,包括一些在网络设备中使用的PCI总线,Flash等设备,这也要求在硬件设计中注意端模式的转换。

    本文提到的小端外设是指这种外设中的寄存器以小端方式进行存储,如PCI设备的配置空间,NOR FLASH中的寄存器等等。对于有些设备,如DDR颗粒,没有以小端方式存储的寄存器,因此从逻辑上讲并不需要对端模式进行转换。在设计中,只需要将双方数据总线进行一一对应的互连,而不需要进行数据总线的转换。

    如果从实际应用的角度说,采用小端模式的处理器需要在软件中处理端模式的转换,因为采用小端模式的处理器在与小端外设互连时,不需要任何转换。而采用大端模式的处理器需要在硬件设计时处理端模式的转换。大端模式处理器需要在寄存器,指令集,数据总线及数据总线与小端外设的连接等等多个方面进行处理,以解决与小端外设连接时的端模式转换问题。在寄存器和数据总线的位序定义上,基于大小端模式的处理器有所不同。

    一个采用大端模式的32位处理器,如基于E500内核的MPC8541,将其寄存器的最高位msb(most significant bit)定义为0,最低位lsb(lease significant bit)定义为31;而小端模式的32位处理器,将其寄存器的最高位定义为31,低位地址定义为0。与此向对应,采用大端模式的32位处理器数据总线的最高位为0,最高位为31;采用小端模式的32位处理器的数据总线的最高位为31,最低位为0。

    大小端模式处理器外部总线的位序也遵循着同样的规律,根据所采用的数据总线是32位,16位和8位,大小端处理器外部总线的位序有所不同。大端模式下32位数据总线的msb是第0位,MSB是数据总线的第0~7的字段;而lsb是第31位,LSB是第24~31字段。小端模式下32位总线的msb是第31位,MSB是数据总线的第31~24位,lsb是第0位,LSB是7~0字段。大端模式下16位数据总线的msb是第0位,MSB是数据总线的第0~7的字段;而lsb是第15位,LSB是第8~15字段。小端模式下16位总线的msb是第15位,MSB是数据总线的第15~7位,lsb是第0位,LSB是7~0字段。大端模式下8位数据总线的msb是第0位,MSB是数据总线的第0~7的字段;而lsb是第7位,LSB是第0~7字段。小端模式下8位总线的msb是第7位,MSB是数据总线的第7~0位,lsb是第0位,LSB是7~0字段。

    由上分析,我们可以得知对于8位,16位和32位宽度的数据总线,采用大端模式时数据总线的msb和MSB的位置都不会发生变化,而采用小端模式时数据总线的lsb和LSB位置也不会发生变化。

    为此,大端模式的处理器对8位,16位和32位的内存访问(包括外设的访问)一般都包含第0~7字段,即MSB。小端模式的处理器对8位,16位和32位的内存访问都包含第7~0位,小端方式的第7~0字段,即LSB。由于大小端处理器的数据总线其8位,16位和32位宽度的数据总线的定义不同,因此需要分别进行讨论在系统级别上如何处理端模式转换。在一个大端处理器系统中,需要处理大端处理器对小端外设的访问。

    十、实际中的例子

    虽然很多时候,字节序的工作已由编译器完成了,但是在一些小的细节上,仍然需要去仔细揣摩考虑,尤其是在以太网通讯、MODBUS通讯、软件移植性方面。这里,举一个MODBUS通讯的例子。在MODBUS中,数据需要组织成数据报文,该报文中的数据都是大端模式,即低地址存高位,高地址存低位。假设有一16位缓冲区m_RegMW[256],因为是在x86平台上,所以内存中的数据为小端模式:m_RegMW[0].low、m_RegMW[0].high、m_RegMW[1].low、m_RegMW[1].high……

    为了方便讨论,假设m_RegMW[0] = 0x3456; 在内存中为0x56、0x34。

    现要将该数据发出,如果不进行数据转换直接发送,此时发送的数据为0x56,0x34。而Modbus是大端的,会将该数据解释为0x5634而非原数据0x3456,此时就会发生灾难性的错误。所以,在此之前,需要将小端数据转换成大端的,即进行高字节和低字节的交换,此时可以调用步骤五中的函数BigtoLittle16(m_RegMW[0]),之后再进行发送才可以得到正确的数据。0b1331709591d260c1c78e86d0c51c18.png

    展开全文
  • 大端模式和小端模式

    万次阅读 多人点赞 2018-08-28 17:09:25
    小端模式(Little-endian):低位字节排放在内存的低地址端,高位字节排放在内存的高地址端,即逆序排列,低尾端; 例(无论是小端模式还是大端模式。每个字节内部都是按顺序排列): 1)大端模式: 低地址 ------...

     

    一.概念

    大端模式(Big-endian):高位字节排放在内存的低地址端,低位字节排放在内存的高地址端,即正序排列,高尾端;

    小端模式(Little-endian):低位字节排放在内存的低地址端,高位字节排放在内存的高地址端,即逆序排列,低尾端;

    例(无论是小端模式还是大端模式。每个字节内部都是按顺序排列):

    1)大端模式:

    低地址 -----------------> 高地址

    0x0A  |  0x0B  |  0x0C  |  0x0D

    2)小端模式:

    低地址 ------------------> 高地址

    0x0D  |  0x0C  |  0x0B  |  0x0A

    3)下面是两个具体例子:

    16bit宽的数0x1234在两种模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

    内存地址小端模式存放内容大端模式存放内容
    0x40000x340x12
    0x40010x120x34

    32bit宽的数0x12345678在两种模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

    内存地址小端模式存放内容大端模式存放内容
    0x40000x780x12
    0x40010x560x34
    0x40020x340x56
    0x40030x120x78

    4)大端小端没有谁优谁劣,各自优势便是对方劣势:

    小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
    大端模式 :符号位的判定固定为第一个字节,容易判断正负。

    二、数组在大端小端模式下的存储:

    以unsigned int num = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示num:
    Big-Endian: 低地址存放高位,如下:

    低地址

    ---------------

    buf[0] (0x12) -- 高位 

    buf[1] (0x34)

    buf[2] (0x56)

    buf[3] (0x78) -- 低位

    ---------------
    高地址
     
    Little-Endian: 低地址存放低位,如下:

    低地址

    ---------------

    buf[0] (0x78) -- 低位

    buf[1] (0x56)

    buf[2] (0x34)

    buf[3] (0x12) -- 高位

    --------------

    高地址

    三、为什么会有大小端模式之分呢?

           这是因为在计算机中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8 bit。但是在C 语言中除了 8 bit 的char之外,还有 16 bit 的 short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着如果将多个字节安排的问题。大端存储模式和小端存储模式也就应运而生。例如一个16bit的short型 x ,在内存中的地址为 0x0010,x 的值为0x1122,那么0x11位高字节,0x22位低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

    四、如何判断机器的字节序 (重点)

    一般都是通过 union 来测试的,下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:

    #include <stdio.h>
    
    int main (void)
    {
    union{
    short i;
    char a[2];
    }u;//联合体u
    
    u.a[0] = 0x11;
    u.a[1] = 0x22;
    
    printf ("0x%x\n", u.i); //0x2211 为小端 0x1122 为大端
    return 0;
    }
    
    输出结果:
    0x2211

          union 型数据所占的空间等于其最大的成员所占的空间。对 union 型的成员的存取都是相对于该联合体基地址的偏移量为 0 处开始,也就是联合体的访问不论对哪个变量的存取都是从 union 的首地址位置开始

         联合是一个在同一个存储空间里存储不同类型数据的数据类型。这些存储区的地址都是一样的,联合里不同存储区的内存是重叠的,修改了任何一个其他的会受影响。那么通过强制类型转换,判断其实存储位置,也可以测试大小端了:

    #include <stdio.h>
    
    int main (void)
    {
    short i = 0x1122;
    char *a = (char*)(&i);
    
    printf ("0x%x\n", *(a + 0)); //大端为 0x11 小端为 0x22
    printf ("0x%x\n", *(a + 1));
    return 0;
    }
    
    输出结果:
    0x22
    0x11

    五、常见的字节序

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

    1)常见CPU的字节序

    Big Endian : PowerPC、IBM、Sun
    Little Endian : x86、DEC
    ARM既可以工作在大端模式,也可以工作在小端模式。

    2)常见文件的字节序

    Adobe PS – Big Endian
    BMP – Little Endian
    DXF(AutoCAD) – Variable
    GIF – Little Endian
    JPEG – Big Endian
    MacPaint – Big Endian
    RTF – Little Endian

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

    六、如何进行大小端转换(重点)

    第一种方法:位操作

    #include<stdio.h>
    typedef unsigned int uint_32 ;
    typedef unsigned short uint_16 ;
    
    //16位
    #define BSWAP_16(x) \
    (uint_16)((((uint_16)(x) & 0x00ff) << 8) | \ (((uint_16)(x) & 0xff00) >> 8) \)
    
    //32位
    #define BSWAP_32(x) \
    (uint_32)((((uint_32)(x) & 0xff000000) >> 24) | \ (((uint_32)(x) & 0x00ff0000) >> 8) | \
    (((uint_32)(x) & 0x0000ff00) << 8) | \ (((uint_32)(x) & 0x000000ff) << 24) \)
    
    //无符号整型16位
    uint_16 bswap_16(uint_16 x)
    {
      return (((uint_16)(x) & 0x00ff) << 8) | \ (((uint_16)(x) & 0xff00) >> 8) ;
    }
    
    //无符号整型32位
    uint_32 bswap_32(uint_32 x)
    {
      return (((uint_32)(x) & 0xff000000) >> 24) | \ (((uint_32)(x) & 0x00ff0000) >> 8) | \
      (((uint_32)(x) & 0x0000ff00) << 8) | \ (((uint_32)(x) & 0x000000ff) << 24) ;
    }
    
    int main(int argc,char *argv[])
    {
     printf("------------带参宏-------------\n");
     printf("%#x\n",BSWAP_16(0x1234)) ;
     printf("%#x\n",BSWAP_32(0x12345678));
     printf("------------函数调用-----------\n");
     printf("%#x\n",bswap_16(0x1234)) ;
     printf("%#x\n",bswap_32(0x12345678));
     return 0 ;
    }
    
    输出结果:
    ------------带参宏-------------
    0x3412
    0x78563412
    ------------函数调用-----------
    0x3412
    0x78563412

    这里有个思考?上面的哪个是转换为大端,哪个是转为小端了呢?

    举个例子,比如数字 0x12 34 56 78在内存中的表示形式为:

    1)大端模式:

    低地址 -----------------> 高地址

    0x12  |  0x34  |  0x56  |  0x78

    2)小端模式:

    低地址 ------------------> 高地址

    0x78  |  0x56  |  0x34  |  0x12

    则:

    转换为大端:

    pPack[2] = (u8)((len >> 8) & 0xFF);
    pPack[3] = (u8)(len & 0xFF);

    转为为小端:

    pPack[2] = (u8)(len & 0xFF);

    pPack[3] =  (u8)((len >> 8) & 0xFF);

     

    第二种方法:从软件的角度理解端模式,使用 htonl, htons, ntohl, ntohs 等函数

    参看:百度百科--htonl ()函数

    参看:百度百科--htons ()函数

    查看:man htonl

    NAME
    htonl, htons, ntohl, ntohs - convert values between host and network byte order
    SYNOPSIS
    #include <arpa/inet.h>
    
    uint32_t htonl(uint32_t hostlong);
    uint16_t htons(uint16_t hostshort);
    uint32_t ntohl(uint32_t netlong);
    uint16_t ntohs(uint16_t netshort);
    
    DESCRIPTION
    The htonl() function converts the unsigned integer hostlong from host byte order to network byte order.
    
    The htons() function converts the unsigned short integer hostshort from host byte order to network byte order.
    
    The ntohl() function converts the unsigned integer netlong from network byte order to host byte order.
    
    The ntohs() function converts the unsigned short integer netshort from network byte order to host byte order.
    
    On the i386 the host byte order is Least Significant Byte first, whereas the network byte order, as used on the Internet, is Most
    
    Significant Byte first.

    解释

    htonl()     //32位无符号整型的主机字节顺序到网络字节顺序的转换(小端->>大端)
    htons() 
        //16位无符号短整型的主机字节顺序到网络字节顺序的转换  (小端->>大端)
    ntohl()     //32位无符号整型的网络字节顺序到主机字节顺序的转换  (大端->>小端)
    ntohs()     //16位无符号短整型的网络字节顺序到主机字节顺序的转换  (大端->>小端)

    注,主机字节顺序,X86一般多为小端(little-endian),网络字节顺序,即大端(big-endian);

    举两个小例子:

    //示例一
    
    #include <stdio.h>
    #icnlude <arpa/inet.h>
    
    int main (void){
      union{
        short i;
        char a[2];
      }u;
       u.a[0] = 0x11;
    
       u.a[1] = 0x22;
    
       printf ("0x%x\n", u.i); //0x2211 为小端 0x1122 为大端
       printf ("0x%.x\n", htons (u.i)); //大小端转换
       return 0;
    }
    
    输出结果:
    0x2211
    0x1122
    //示例二
    
    #include <stdio.h>
    #include <arpa/inet.h>
    
    struct ST{
    short val1;
    short val2;
    };
    
    union U{
    int val;
    struct ST st;
    };
    
    int main(void)
    {
    int a = 0;
    union U u1, u2;
    a = 0x12345678;
    u1.val = a;
    
    printf("u1.val is 0x%x\n", u1.val);
    printf("val1 is 0x%x\n", u1.st.val1);
    printf("val2 is 0x%x\n", u1.st.val2);
    printf("after first convert is: 0x%x\n", htonl(u1.val));
    
    u2.st.val2 = htons(u1.st.val1);
    u2.st.val1 = htons(u1.st.val2);
    printf("after second convert is: 0x%x\n", u2.val);
    return 0;
    }
    
    输出结果:
    u1.val is 0x12345678
    val1 is 0x5678
    val2 is 0x1234
    after first convert is: 0x78563412
    after second convert is: 0x78563412
    
    

            在对普通文件进行处理也需要考虑端模式问题。在大端模式的处理器下对文件的32,16位读写操作所得到的结果与小端模式的处理器不同。单纯从软件的角度理解上远远不能真正理解大小端模式的区别。事实上,真正的理解大小端模式的区别,必须要从系统的角度,从指令集,寄存器和数据总线上深入理解,大小端模式的区别。 

    七.验证当前机器系统的存储方式是大端还是小端

    #include <stdio.h>
    #include <conio.h>
    union Test {
    	short num;
    	char c[sizeof(short)];
    };
    int main()
    {
    	union Test t;
    	t.num = 0x0102;
    	if (t.c[0] == 1 && t.c[1] == 2)
    		printf("大端!\n");
    	else if (t.c[0] == 2 && t.c[1] == 1)
    		printf("小端!\n");
    	else
    		printf("未知!\n");
    	getchar();
        //system("PAUSE"); C函数,C++中需包含头文件#include<stdlib.h>
    	return 0;
    }

     

    展开全文
  • 小端模式Little-Endian:低字节存于内存低地址,高字节存于内存高地址。 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。 首先我们来看下数据在大小端两...
  • 内存地址 0x00000001 0x00000002 0x00000003 0x00000004 大端模式 0x12 0x34 0x56 0x78 小端模式 0x78 0x56 0x34 0x12 再换一种图示:同样以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储...
  • CPU大小端模式

    千次阅读 2022-02-27 18:54:04
    By: Ailson Jack Date: 2022.02.27 ... 不同体系结构的CPU对于数据在内存中...数据在内存中的存储是以字节(byte)为单位的,因此对于半字(Half-Word)和字(Word)在内存中就有两种存储顺序,分别称为:大端模式(Big
  • 大端模式与小端模式

    千次阅读 2021-12-08 15:29:54
    小端模式:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,数据从低位往高位放;这和我们的阅读习惯一致。 ...
  • 00. 目录 文章目录00. 目录01. 概述02. 示例分析03....小端模式(Little-endian):低位字节排放在内存的低地址端,高位字节排放在内存的高地址端,即逆序排列,低尾端; 例(无论是小端模式还是...
  • 小端模式 数据的低位放在低地址空间,数据的高位放在高地址空间 简记:小端就是低位对应低地址,高位对应高地址 存放二进制数:1011-0100-1111-0110-1000-1100-0001-0101 注意注意:我们在存放的时候是以一个存储...
  • 大小端模式,stm32采用小端模式

    千次阅读 2018-07-19 21:45:30
    存储模式:小端:较高的有效字节存储在较高的存储器地址,较低的有效字节存储...STM32 属于小端模式,简单地说:比如:temp=0X12345678;假设temp的地址为:0X4000 0000那么,在内存里面,其存储就变成了:| 地址 ...
  • 大小端模式以及两种判断方法

    千次阅读 2019-04-12 13:55:01
    - 大端:高尾端:数据的尾部(低位字节)放在内存的高位地址。 - 小端:低尾端:数据的尾部(低位字节)放在内存的地位地址。
  • stm32是大端模式还是小端模式

    千次阅读 2021-10-29 22:16:02
    1.大端模式 是指数据的高字节保存在内存的低地址中, 而数据的低字节保存在内存的高地址中, 这样的存储模式有点儿类似于把数据当作字符串顺序处理: ...3、stm32是小端模式,如一个32位无符号数0x1...
  • 大端模式和小端模式通俗说明

    千次阅读 2020-02-25 22:20:17
    大端模式和小端模式 这两个模式我们经常听说,平时的协议里面也经常看见这两个词语,这两个词语主要是用来说明字节的排序方式的。 大端模式 大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在...
  • 正确区分大小端模式

    千次阅读 2020-03-18 15:38:52
    正确区分大小端模式 嵌入式开发经常会遇到大小端的问题,往往学习后,过一段时间就又忘记了,这里总结一下,希望给大家留下深刻的记忆。 字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端...
  • [python]大端模式和小端模式

    千次阅读 2020-10-16 10:16:51
    计算机有little endian(小端模式)和big endian(大端模式)之分,它们都是数据在内存中的表示方式。 大端模式:左边为字节的高有效位,右边为低有效位。数的高有效字节放在存储器的低位置,数的低有效字节放在...
  • 本文主要描述大端小端的概念,分类和区别,还讲述了他们的由来,以及各自的优缺点,对初识者具有很大的帮助
  • 什么是大端模式和小端模式

    千次阅读 2019-10-31 15:35:48
    小端模式(little endian):低位(字节/比特)放在低地址中,高位(字节/比特)放在高地址中。 在串口等串行通信中,一次只能发1个字节。这个时候遇到一个问题。int类型有4个字节。我们是按照什么顺序发送字节呢...
  • C语言大小端模式

    千次阅读 2018-01-07 12:56:23
    大端模式(big endian)和小端模式(little endian) (1)最早出现在小说的词,和计算机无关 (2)后来用于计算机通信,在串行通信中,一次只能发送一个字节,这样发送一个int就有问题。 规则就是发送方和接受方...
  • 转自 https://blog.csdn.net/ce123_zhouwei/article/details/6971544详解大端模式和小端模式一、大端模式和小端模式的起源 关于大端小端名词的由来,有一个有趣的故事,来自于Jonathan Swift的《格利佛游记》:...
  • 什么是大端模式,什么是小端模式? 所谓的大端模式(Big-endian),是指数据的高字节,保存在内存的低地址中,而数据的低字节,保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由...
  • 大端模式小端模式

    万次阅读 2017-03-30 14:41:35
    介绍大端和小端的知识
  • stm32大小端模式

    千次阅读 2020-02-17 17:08:06
    stm32存储方式为小端模式 大端模式:数据高字节保存在内存低地址中,数据低字节保存在内存高地址中 小端模式:数据高字节保存在内存高地址中,数据低字节保存在内存低地址中 ...
  • 1、小端模式:当一个数的二进制的高位存在内存格子的高地址的格子中,或者是低位存储在低地址的格子中,它就叫小端模式。 2、大端模式:个小端模式相反,就是数据的高位放在了低地址的内存格子中,或者是数据的...
  • 大端模式和小端模式转化

    千次阅读 2018-08-27 13:28:11
    在工作中遇到一个问题,数据是以大端模式存储的,而机器是小端模式,必须进行转换,否则使用时会出问题。 一、定义: 大端模式(Big Endian):数据的高字节,保存在内存的低地址中;数据的低字节,保存在内存的高...
  • 如何判断大端模式和小端模式

    千次阅读 2019-08-30 16:04:58
  • C/C++之大端模式和小端模式

    千次阅读 2018-02-18 11:47:25
    32位宽的数0x12345678在小端模式CPU内存中的存放方式(假设从地址0x4000开始存放)为: 内存地址 0x4000 0x4001 0x4002 0x4003 存放内容 0x78 0x56 0x34 0x12 而在大端模式CPU内存中的存放方式则为: 内存地址 0x...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 641,187
精华内容 256,474
关键字:

小端模式

友情链接: yuv444.zip