Big Endian与Little Endian区别

共同体存放的顺序是所有成员都从低地址开始存放。利用该特性可判断CPU内存采用Little-endian或者Big-endian模式、、、

#include<stdio.h>
int main()
{
union   _UnionTest
{
unsigned int    i;
unsigned char   ch[2];
};
_UnionTest uniontest;
uniontest.i = 0x1420;
printf("%d\t%d\n", uniontest.ch[0], uniontest.ch[1]);

}

结果:32   20

ARM体系中,每个字单元包含4个字节单元或者两个半字单元。在字单元中,4个字节哪一个是高位字节,哪一个是低位字节则有两种不同的格式:big-endian和little-endian格式。在小端模式中,低位字节放在低地址,高位字节放在高地址;在大端模式中,低位字节放在高地址,高位字节放在低地址。

采用大小模式对数据进行存放的主要区别在于在存放的字节顺序,大端方式将高位存放在低地址,小端方式将低位存放在低地址

在C语言中,联合体union的存放顺序是所有成员都从低地址开始存放的。利用这一特点,可以用联合体变量判断ARM或x86环境下,存储系统是是大端还是小端模式。

网络编程中,TCP/IP统一采用big-endian方式(网络字节序);

  具体的代码如下:

#include "stdio.h"
int main()
{
  union w
 {
  short int a; 
  char b; //1 byte
 } c;
  c.a=1;
  if (c.b==1)
  printf("It is Little_endian!/n");
  else
  printf("It is Big_endian!/n");
  return 1;
}

为什么要注意字节序的问题呢?你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。但是,如果你的程序要跟别人的程序产生交互呢?在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,JAVA编写的程序则唯一采用big endian方式来存储数据。试想,如果你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的0x12345678来说,你的程序传递给别人的一个数据,将指向0x12345678的指针传给了JAVA程序,由于JAVA采取big endian方式存储数据,很自然的它会将你的数据翻译为0x78563412。什么?竟然变成另外一个数字了?是的,就是这种后果。因此,在你的C程序传给JAVA程序之前有必要进行字节序的转换工作。

    
无独有偶,所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。ANSI C中提供了下面四个转换字节序的宏。

big endian:最高字节在地址最低位,最低字节在地址最高位,依次排列。
little endian
:最低字节在最低位,最高字节在最高位,反序排列。

endian指的是当物理上的最小单元比逻辑上的最小单元小时,逻辑到物理的单元排布关系。咱们接触到的物理单元最小都是byte,在通信领域中,这里往往是bit,不过原理也是类似的。

三、Big Endian Little Endian优劣

来自:Dr. William T. Verts, April 19, 1996

Big Endian

判别一个数的正负很容易,只要取offset0处的一个字节就能确认。

Little Endian

长度为124字节的数,排列方式都是一样的,数据类型转换非常方便。

  • Adobe Photoshop -- Big Endian
  • BMP (Windows and OS/2 Bitmaps) -- Little Endian
  • DXF (AutoCad) -- Variable
  • GIF -- Little Endian
  • IMG (GEM Raster) -- Big Endian
  • JPEG -- Big Endian
  • FLI (Autodesk Animator) -- Little Endian
  • MacPaint -- Big Endian
  • PCX (PC Paintbrush) -- Little Endian
  • PostScript -- Not Applicable (text!)
  • POV (Persistence of Vision ray-tracer) -- Not Applicable (text!)
  • QTM (Quicktime Movies) -- Little Endian (on a Mac!) (PeterLee注Big Endian in my opinion)
  • Microsoft RIFF (.WAV & .AVI) -- Both
  • Microsoft RTF (Rich Text Format) -- Little Endian
  • SGI (Silicon Graphics) -- Big Endian
  • Sun Raster -- Big Endian
  • TGA (Targa) -- Little Endian
  • TIFF -- Both, Endian identifier encoded into file
  • WPG (WordPerfect Graphics Metafile) -- Big Endian (on a PC!)
  • XWD (X Window Dump) -- Both, Endian identifier encoded into file 
很多人认为掌握这个知识是不必要,其实不然.在网络编程中,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[i] = data % 256;
        // 或者可以:
        //cmd[i] = 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[i];        
    }
        
    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[i]);
    }


    // 再以相反的顺序保存数据到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;
}

http://bbs.chinaunix.net/thread-823662-1-1.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值