big endian 和 little endian

http://www.chinaunix.net 作者:converse  发表于:2006-10-30 18:31:18
发表评论】【查看原文】【C/C++讨论区】【关闭

little endian和big endian是表示计算机字节顺序的两种格式,所谓的字节顺序指的是长度跨越多个字节的数据的存放形式.
        假设从地址0x00000000开始的一个字中保存有数据0x1234abcd,那么在两种不同的内存顺序的机器上从字节的角度去看的话分别表示为:
       1)little endian:在内存中的存放顺序是0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12
       2)big  endian:在内存中的存放顺序是0x00000000-0x12,0x00000001-0x34,0x00000002-0xab,0x00000003-0xcd
       需要特别说明的是,以上假设机器是每个内存单元以8位即一个字节为单位的.
       简单的说,ittle endian把低字节存放在内存的低位;而big endian将低字节存放在内存的高位.
       现在主流的CPU,intel系列的是采用的little endian的格式存放数据,而motorola系列的CPU采用的是big endian.
       
       以下是判断字节存储顺序的可移植的C语言代码:

/********************************************************************
created: 2006-9-5
filename:  test.cpp
author: 李创

purpose: 可移植的用于判断存储格式是
                little endian还是big ednian的C代码
                取自<<C: A Reference Manual>>
*********************************************************************/

#include <stdio.h>

union
{
long Long;
char Char[sizeof(long)];
}u;

int main()
{
u.Long = 1;

if (u.Char[0] == 1)
{
printf("Little Endian!/n");
}
else if (u.Char[sizeof(long) - 1] == 1)
{
printf("Big Endian!/n");
}
else
{
printf("Unknown Addressing!/n");
}

    printf("Now, Let's look at every byte in the memory!/n");
    for (int i = 0; i < sizeof(long); ++i)
    {
        printf("[%x] = %x/n", &u.Char
, u.Char);
    }

return 0;
}


 很多人认为掌握这个知识是不必要,其实不然.在网络编程中,TCP/IP统一采用big endian方式传送数据,也就是说,假设现在是在一个字节顺序是little endian的机器上传送数据,要求传送的数据是0XCEFABOBO,那么你就要以0XBOBOFACE的顺序在unsigned int中存放这个数据,只有这样才能保证存放的顺序满足TCP/IP的字节顺序要求.很多时候,需要自己编写应用层的协议,字节顺序的概念在这个时候就显得及其的重要了.
       下面给出的是在big endian和little endian中相互转换的代码,C语言强大的位操作的能力在这里显示了出来:


/********************************************************************
created: 2006-9-5
filename:  get32put32.cpp
author: 李创

purpose: 在little endian和big ednian之间相互转化数据的演示代码

*********************************************************************/


#include <stdio.h>

const unsigned char SIZE_OF_UNSIGNEDINT  = sizeof(unsigned int);
const unsigned char SIZE_OF_UNSIGNEDCHAR = sizeof(unsigned char);

void put_32(unsigned char *cmd, unsigned int data)
{
    int i;
    for (i = SIZE_OF_UNSIGNEDINT - 1; i >= 0; --i)
    {
        cmd
 = data % 256;
        // 或者可以:
        //cmd
 = data & 0xFF;
        data = data >> 8;
    }
}

unsigned int get_32(unsigned char *cmd)
{
    unsigned int  ret;
    int i;

    for (ret = 0, i = SIZE_OF_UNSIGNEDINT - 1; i >= 0; --i)
    {
        ret  = ret << 8;
        ret |= cmd
;        
    }

    return ret;
}

int main(void)
{
    unsigned char cmd[SIZE_OF_UNSIGNEDINT];
    unsigned int data, ret;
    unsigned char *p;
    int i;

    data = 0x12345678;
    printf("data = %x/n", data);
    // 以字节为单位打印出数据
    p = (unsigned char*)(&data);
    for (i = 0; i < SIZE_OF_UNSIGNEDINT; ++i)
    {
        printf("%x", *p++);
    }
    printf("/n");

    // 以相反的顺序存放到cmd之中
    put_32(cmd, data);
    for (i = 0; i < SIZE_OF_UNSIGNEDINT; ++i)
    {
        printf("cmd[%d] = %x/n", i, cmd
);
    }

    // 再以相反的顺序保存数据到ret中
    // 保存之后的ret数值应该与data相同
    ret = get_32(cmd);
    printf("ret = %x/n", ret);
    p = (unsigned char*)(&ret);
    for (i = 0; i < SIZE_OF_UNSIGNEDINT; ++i)
    {
        printf("%x", *p++);
    }
    printf("/n");

    return 0;
}


参考资料:<<C: A Reference Manual>>

[ 本帖最后由 converse 于 2006-10-30 17:30 编辑 ]


 coldwarm 回复于:2006-09-05 21:40:35

ittle endian:0xcdab3412,即0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12

little endian把低位存放到高位

上面的说反了吧.little endian应当是
0x00000000-0x12
0x00000001-0x34
....
这样的吧.

little endian把低字节存放到低地址,把高字节放到高地址.
数据0xcdab3412从左到右,由高字节到低字节,由高地址到低地址.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    int value = 0x12345678;

    union ValueT
    {
        int value;
        char data[4];
    } a;
    a.value = 0x12345678;
    printf("value is 0x%x/n", a.value);
    printf("address is %p, 0x%x/n",&a.data[0], a.data[0]);
    printf("address is %p, 0x%x/n",&a.data[1], a.data[1]);
    printf("address is %p, 0x%x/n",&a.data[2],  a.data[2]);
    printf("address is %p, 0x%x/n", &a.data[3], a.data[3]);

    exit(EXIT_SUCCESS);
}

value is 0x12345678
address is 0xbffffa0c, 0x78
address is 0xbffffa0d, 0x56
address is 0xbffffa0e, 0x34
address is 0xbffffa0f, 0x12

[ 本帖最后由 coldwarm 于 2006-9-5 21:56 编辑 ]

 converse 回复于:2006-09-05 22:21:10

引用:
原帖由 coldwarm 于 2006-9-5 21:40 发表
ittle endian:0xcdab3412,即0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12

little endian把低位存放到高位

上面的说反了吧.little endian应当是
0x00000000-0x12
0x00000001-0x34
. ... 




感谢指出错误,我的描述有问题,应该是这样:

引用:

       假设从地址0x00000000开始的一个字中保存有数据0x1234abcd,那么在两种不同的内存顺序的机器上从字节的角度去看的话分别表示为:
       1)little endian:在内存中的存放顺序是0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12
       2)big  endian:在内存中的存放顺序是0x00000000-0x12,0x00000001-0x34,0x00000002-0xab,0x00000003-0xcd


你可能感兴趣的:(编程,c,cmd,存储,语言,Motorola)