http://www.cnblogs.com/Romi/archive/2012/01/10/2318551.html

当前的存储器,多以byte为访问的最小单元,当一个逻辑上的地址必须分割为物理上的若干单元时就存在了先放谁后放谁的问题,于是端(endian)的问题应运而生了,对于不同的存储方法,就有大端(big-endian)和小端(little- endian)两个描述。

字节排序按分为大端和小端,概念如下

大端(big endian):低地址存放高有效字节

小端(little endian):低字节存放地有效字节

现在主流的CPU,intel系列的是采用的little endian的格式存放数据,而motorola系列的CPU采用的是big endian,ARM则同时支持 big和little,网络编程中,TCP/IP统一采用大端方式传送数据,所以有时我们也会把大端方式称之为网络字节序。

特别需要注意的是,C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而 JAVA编写的程序则唯一采用big endian方式来存储数据。这里我就只讨论C/C++语言的情况。

1.大端和小端的方式及判断

举个例子说明,我的机子是32位windows的系统,处理器是AMD的。对于一个int型数0x12345678,为方便说明,这里采用16进制表示。这个数在不同字节顺序存储的CPU中储存顺序如下:

0x12345678   16进制,两个数就是一字节

高有效字节——>低有效字节: 12 34 56 78

          低地址位     高低址位

大端:  12  34        56   78

小端: 78  56        34   12

下面验证下本机CPU属于哪种字节存储顺序。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
 
using namespace std;
 
typedef unsigned int UINT;
typedef unsigned char UCHAR;
 
int main()
{
    UINT i=0x12345678;
    cout<<hex<<i<<endl;
    UCHAR *p = (UCHAR*)&i;          //将i的地址传给数组指针p,实际上p指向的地址是i在内存中存储的第一个字节,大端就是0x12,小端就是0x78
    if((*p==0x78)&(*(p+1)==0x56))       
        cout<<"小端"<<endl;
    else if((*p==0x12)&(*(p+1)==0x34))
        cout<<"大端"<<endl;
    else
        cout<<"这是神马字节顺序呢?";
    return 0;
}

调试显示时小端,我用的机子字节存储为小端方式。

2.大端和小端的字节转换

当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序(即大端方式)后再进行传输。此外用C/C++在小端方式的机器上编写的程序与java程序互通时也要进行大端和小端的转换。

这里所谓转换就是改变字节的排序,使交互时数据保持一致。举一个例子,还是16进制表示的数0x12345678,在小端机器上排序为0x78563412,当内存中这样的数传输时,在大端方式下就是0x78563412这个值,与原值不同,要想与原值相同,在传输前,在大端方式下就该是0x12345678,这时原数在内存中为0x12345678,即将原数据0x12345678在内存存储序列为0x12345678,也就是要转换成大端方式。

要传输值:12 34 56 78

不转换时,小端:78 56 34 12

转换为大端:12 34 56 78

根据上面的大端和小端字节排序,可以方便的用移位运算完成转换功能。从小端转到大端代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
 
using namespace std;
 
typedef unsigned int UINT;
typedef unsigned char UCHAR;
 
int main()
{
    UINT i=0x12345678;
    cout<<hex<<i<<endl;
    UCHAR *p = (UCHAR*)&i;
    UINT num,num1,num2,num3,num4;
    num1=(UINT)(*p)<<24;
    num2=((UINT)*(p+1))<<16;
    num3=((UINT)*(p+2))<<8;
    num4=((UINT)*(p+3));
    num=num1+num2+num3+num4;
 
    cout<<"num1:"<<hex<<num1<<endl;     //看num1的16进制表示,下同
    cout<<"num2:"<<hex<<num2<<endl;
    cout<<"num3:"<<hex<<num3<<endl;
    cout<<"num4:"<<hex<<num4<<endl;
    cout<<"num:"<<hex<<num<<endl;
 
    unsigned char *q = (unsigned char*)&num;
    if((*q==0x78)&(*(q+1)==0x56))         
        cout<<"小端"<<endl;
    else if((*q==0x12)&(*(q+1)==0x34))
        cout<<"大端"<<endl;
    else
        cout<<"这是神马字节顺序呢?";
    return 0;
}

至于说(UINT)(*p)为什么要移24位,其实是很好理解的,将0x00000012变成0x12000000,不就是向左移24位吗。

当然,向上面这样写时为了方便理解,可以更简单的写一个函数用于完成上面的转换功能,函数如下:

1
2
3
4
5
UINT EndianConvertLToB(UINT InputNum) {
    UCHAR *p = (UCHAR*)&InputNum;
    return(((UINT)*p<<24)+((UINT)*(p+1)<<16)+
               ((UINT)*(p+2)<<8)+(UINT)*(p+3));
}

同样的原理适用于大端转小端,但是大端转小端时移位有差别,函数如下:

1
2
3
4
5
UINT EndianConvertBToL(UINT InputNum) {
    UCHAR *p = (UCHAR*)&InputNum;
    return(((UINT)*p)+((UINT)*(p+1)<<8)+
               ((UINT)*(p+2)<<16)+(UINT)*(p+3)<<24);
}

大端(big endian)和小端(little endian)的更多相关文章

  1. 大端(Big Endian)与小端(Little Endian)

    1. 你从哪里来?端模式(Endian)的这个词出自Jonathan Swift书写的<格列佛游记>.这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big ...

  2. Java中如何判断当前环境是大端字节顺序还是小端字节顺序

    Java非字节类型的基本类型,除了布尔型都是由组合在一起的几个字节组成的.这些数据类 型及其大小总结在表 2-1 中. 表:基本数据类型及其大小 数据类型 大小(以字节表示) Byte 1 Char ...

  3. 大端(bigend)与小端(littleend)

                                      大端:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中: 小端:是指数据的高位保存在内存的高地址中,而数据的高 ...

  4. 〖Linux〗使用sed命令修改小端(little endian)存储的数据

    #!/bin/bash - #=============================================================================== # # F ...

  5. 转!大端模式&小端模式

    大端模式&小端模式   在C语言中除了8位的char型之外,还有16位的short型,32位的long型(要看具体的编译器),对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器 ...

  6. java的大端小端和c#如何对应

    当前的存储器,多以byte为访问的最小单元,当一个逻辑上的地址必须分割为物理上的若干单元时就存在了先放谁后放谁的问题,于是端(endian)的问题应运而生了,对于不同的存储方法,就有大端(big-en ...

  7. 大端模式 VS 小端模式

    简单点说,就是字节的存储顺序,如果数据都是单字节的,那怎么存储无所谓了,但是对于多字节数据,比如int,double等,就要考虑存储的顺序了.注意字节序是硬件层面的东西,对于软件来说通常是透明的.再说 ...

  8. 关于byte[]字节传输的大端和小端小议

    当前的存储器,多以byte为访问的最小单元,当一个逻辑上的地址必须分割为物理上的若干单元时就存在了先放谁后放谁的问题,于是端(endian)的问题应运而生了,对于不同的存储方法,就有大端(big-en ...

  9. 判别linux机器字节序为大端还是小端

    代码如下: #include <iostream> #include <arpa/inet.h> #include <cstdio> using namespace ...

随机推荐

  1. 内部类访问局部变量的时候,为什么变量必须加上final修饰

    这里的局部变量就是在类方法中的变量,能访问方法中变量的类当然也是局部内部类了.我们都知道,局部变量在所处的函数执行完之后就释放了,但是内部类对象如果还有引用指向的话它是还存在的.例如下面的代码: cl ...

  2. eclipse中文乱码问题解决方案

    eclipse之所以会出现乱码问题是因为eclipse编辑器选择的编码规则是可变的.一般默认都是UTF-8或者GBK,当从外部导入的一个工程时,如果该工程的编码方式与eclipse中设置的编码方式不同 ...

  3. PHP开发APP接口----单例模式连接数据库

    <?php //单例模式 class Db{ static private $_instance; static private $_connectSource; private $_dbCon ...

  4. MongoDB之bson的介绍

    MongoDB之bson的介绍 1. 什么是bson BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON,它和JSON一样,支持内嵌的文档对象和数组对象,但是BSON有JS ...

  5. CentOS 设置网络(修改IP&修改网关&修改DNS)--update.14.08.15

    自己电脑上装的虚拟机用桥接方式连接物理机,虚拟机重启后ip会发生变化,非常阻碍Xshell的连接和hosts指定的dns. 通过修改IP为static模式,保持IP不变. ============== ...

  6. html5移动web开发笔记

    width指定虚拟窗口的屏幕宽度大小. height指定虚拟窗口的屏幕高度大小. initial-scale 指定初始缩放比例. maximum-scale指定允许用户缩放的最大比例. minimum ...

  7. hibernate criteria中Restrictions的用法

    方法说明 方法 说明 Restrictions.eq = Restrictions.allEq 利用Map来进行多个等于的限制 Restrictions.gt > Restrictions.ge ...

  8. javascript,css延迟加载器

    /** * js/css LazyLoad * * 变量hash记录已经加载过的资源,避免重复加载 * * Z.loadScript('a.js', function() { ... }) * * Z ...

  9. userdate和table类型的效率对比

    做cocos2d-x开发的人可能有不少人在实现类时会利用cocos2d-x自己给出的类的实现,也即在luaBinding目录下extern.lua的文件中给出的实现: --Create an clas ...

  10. Linux 4.6分支已到生命尽头 请尽快升级至Linux 4.7.1

    导读 在Linux Kernel 4.7首个维护版本发布的同时,Greg Kroah-Hartman同时也向社区发布了Linux Kernel 4.6.7版本.作为Linux 4.6分支的第7个维护版 ...