也谈大小端

来源:互联网 发布:精子优化处理检查 必要 编辑:程序博客网 时间:2024/06/05 05:10

    大小端问题是一个很简单的概念,但在实际使用中却是一个所必须考虑的非常重要的细节。虽然简单却也曾经困扰过我很多次,今天正好有空整理出来做个笔记。

    字节序的大小端通常指的是在一个字内(32位或者64位)各字节在内存中的存放顺序。注意这里仅是一个字内Byte的顺序,各个字之间的顺序不受大小端的影响。另外还要注意想一个int数据进行左右移位是跟大小端没关系的,因为编译器已经屏蔽了这层差异,不要混淆。另外值得注意的一点是,字节内的bit位也是有大小端区分的,这个在通信协议中需要重点关注。

  1)在Big Endian的情况下,"排在前面的是高位"

a. 对于顺序的两个字节来说,第一个字节是高位(排在前面),第二个字节是低位(排在后面)。

b. 对于字节内部的位来说,

-------most significant bits排在前面,是高位,

-------least significant bits排在后面,是低位。

  2)在Little Endian的情况下,"排在前面的是低位"

a. 对于顺序的两个字节来说,第一个字节是低位(排在前面),第二个字节是高位(排在后面)。

b. 对于字节内部的位来说,

-------least significant bits排在前面,是低位,

-------most significant bits排在后面,是高位。


    大端中一个字内的高有效位在低地址,低有效位在高地址;小端正好相反。

    下面以0x12345678,在大端情况下在内存的存放为:

内存地址 :   0x10000000  0x10000001  0x10000002  0x10000003

大端:            0x12                0x34                0x56                0x78

小端:            0x78                0x56                0x34                0x12

    可见小端正好和我们日常的书写顺序相反,助记口诀----小反(三国杀中的反贼角色)。

    在实际编码中,我们经常需要将一个buffer数组转换成大小端相关的uint32。来看一个例子:

    在实际使用中多是,主机字节序与网络字节序(或者寄存器读出来的数据)之间的转换,转换类型有三种:

1、U32或者U16字节序转换;

2、UCHAR数组和UINT32之间的相互转换;

3、结构体中位域的大小端(参见我的另外一篇博客--位域与大小端);

下面是几个例子:

1.1     判 断大小端代码

judge_endian()

{

         uint a= 1;

         if (*((char *)&a))

                   printf(“BIGEndian\r\n”);

}

1.1.2       UINT字节序转换

htonl的意思是 host to network long

 

#if defined(LE_HOST)

#define htonl(_l)           _ swap32(_l)

#define htons(_s)           _ wap16(_s)

#define ntohl(_l)           _ swap32(_l)

#define ntohs(_s)           _ swap16(_s)

#else

#define htonl(_l)           (_l)      

#define htons(_s)           (_s)      

#define ntohl(_l)           (_l)      

#define ntohs(_s)           (_s)      

#endif

unsigned int _swap32(unsigned int i)

{

   i = (i << 16) | (i >> 16);

   return (i & 0xff00ffff) >> 8 | (i & 0xffff00ff) <<8;

}

unsigned short _swap16(unsigned short i)

{

    return i << 8 | i >> 8;

}

1.1.3       UINT与char数组字节序转换

-->char数组

chipc_spi_read(uint8 * buf, int len)

{

/* chipc_spi_fifo_readword读取寄存器,返回uint类型*/

/*将获取到的value值根据字节序转换到char数组中去*/

#if defined(BE_HOST)

    value = 0;

    for (idx =0 ; idx < len ; idx++) {

        m = idx% 4;

        if (m== 0) {

           value = chipc_spi_fifo_readword();

        }

        *buf++= (uint8)(value >> ((3-m)*8));

    }

#else

    value = 0;

    for (idx =0 ; idx < len ; idx++) {

        m = idx% 4;

        if (m== 0) {

           value = chipc_spi_fifo_ readword ();

        }

        *buf++= (uint8)(value >> (m*8));

    }

#endif

}

char数组-->

chipc_spi_write_fifo(uint8 *data, int len)

{

/*char数组的值转换成uint,然后通过chipc_spi_fifo_writeword函数写到寄存器里去*/

#if defined(BE_HOST)   

    value = 0;

    for (idx =0 ; idx < len ; idx++) {

        m = idx% 4;

        value|= (*data << ((3-m)*8));

        data++;

        if ((m== 3) || (idx == (len - 1))) {

           chipc_spi_fifo_writeword(value);

           value = 0;

        }

    }

#else

    value = 0;

    for (idx =0 ; idx < len ; idx++) {

        m = idx% 4;

        value|= (*data << (m*8));

        data++;

        if ((m== 3) || (idx == (len - 1))) {

            chipc_spi_fifo_writeword(value);

           value = 0;

        }

    }

#endif

}