大端序和小端序

大端序和小端序

一、什么是大端和小端

  1. 大端(Big-Endian):低地址(索引)存放高位字节
  2. 小端(Little-Endian):低地址(索引)存放低位字节

例如:数字0x12345678在内存中的表示形式为:
1. 大端序
0x12|0x34|0x56|0x78 低地址——>高地址
2. 小端序
0x78|0x56|0x34|0x12

内存地址 小端 大端
0x0001 0x78 0x12
0x0002 0x56 0x34
0x0003 0x34 0x56
0x0004 0x12 0x78

大端序是按照数字的书写顺序进行存储的,而小端序是颠倒书写顺序进行存储的。

二、如何判断底层硬件是大端还是小端

2.1 Java中判断的方法

在java.nio.ByteOrder类中有方法nativeOrder()可以判断JVM底层硬件CPU的大小端信息(本机字节顺序)。此方法的定义使得对性能敏感的Java代码能分配字节顺序与硬件相同的直接缓冲区。本机代码库通常在使用此类缓冲区时更为高效。
/*
* 测试本机字节顺序
*/

import java.nio.ByteOrder;

    public class EndianTest {
        public static void main(String[] args) throws IOException{
            if(ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN){
                System.out.println("Big Endian");
            }
            else System.out.println("little Endian");               
        }
    }

在Windows Intel上输出的结果是:little Endian。

现在主流的CPU,intel系列的是采用的little endian的格式存放数据,而motorola系列的CPU采用的是big endian,ARM则同时支持 big和little。

特别需要注意的是,C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而 JAVA编写的程序则唯一采用big endian方式来存储数据。所以JVM采用的其实是大端序。可以通过将整形转成字节数组,或者字节数组转成整形的方式进行判断。

//测试JVM字节序
import java.io.ByteArrayInputStream;
    import java.io.DataInputStream;
    import java.io.IOException;

    public class EndianTest {

        public static void testJvm() throws IOException
        {
            byte[] byteAr = new byte[]{0x78,0x56,0x34,0x12};
            ByteArrayInputStream bais = new ByteArrayInputStream(byteAr);
            DataInputStream dis = new DataInputStream(bais);
            System.out.println(Integer.toHexString(dis.readInt()));
        }
        public static void main(String[] args) throws IOException{
            testJvm();
        }   
    }

输出结果是:78563412
可以说明它是大端序。

用c语言判断底层硬件是大端还是小端

bool IsBigEndian()
    {
        int a =1 ; 
        if(((char*)&a)[3] ==1)
            return true ;
        else
            return false ;
    }

联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写:

bool IsBigEndian()
    {
        union
        {
            unsigned short a ;
            char b ;
        } c;

        c.a =0x0102 ;

        if(c.b ==1)
            return true ;
        else
            return false ;
    }

Union是一个特殊的结构,其中所有成员共享结一个内存地址,任意时间只能存储一个成员。

三、网络字节序

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

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

由于java采用的字节序同网络协议采用的字节序是一样的,它们都是选择的人们通常更容易理解的大端模式(big endian),所以java在接收网络数据是不需要像C/C++那样先调用ntohl和ntohs实现网络字节序与主机字节序的转换,java程序可以直接接收网络数据来进行处理。然而在与采用不同字节序的语言所编写的程序进行通信时,java程序中通常要进行数据类型的转换和解析。

转换的方法见:http://blog.csdn.net/wtbee/article/details/11297643

你可能感兴趣的:(java基础,大端序,小端序)