字节序
字节顺序,又称之为:端序 或 尾序。在计算机科学领域中指的是:电脑内存 或者在网络通讯链路中,由多个字节组成的字的排列方式。
由于不同架构的CPU处理多个字节数据的顺序不一样,比如x86的是小段端模式,KEIL C51是大端模式。但是后来互联网流行,TCP/IP协议规定为大端模式,又称为:network order。
大端和小端
在计算机体系中我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。
在编程语言中一个long类型占32bit,那就需要4个字节来存储,那按照什么样的顺序将这四个字节写到内存中?
因此就出现了大端存储模式和小端存储模式。
大端(Big-Endian): 数据的高位字节在前(内存的低地址),低位字节在后。这样的存储模式类似于把数据当做字符串处理,内存地址由小到大增长,而数据从高位字节开始写入。
这种方式符合人类的阅读习惯!
小端(Little-Endian): 数据的低位字节在前(内存的低地址),高位字节在后。这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
示例:
如:
32位的16进制数:0x1A2B3C4D 在内存中的存储
1 2 3 4
| 内存地址: 00 01 02 03 ------------------------------ 小端模式: 4D 3C 2B 1A 大端模式: 1A 2B 3C 4D
|
java中的大端和小端
Java二进制文件中的所有内容均按大端顺序存储。这种存储方式也被称为network order。这意味着,如果仅仅是用java,则在所有的平台上(如Mac、 PC、 UNIX等)
所有文件的处理方式都相同,可以自由的进行二进制文件的交换,而无需担心字节顺序的问题。
java对我们隐藏了内部字节顺序的问题!
但是当我们与某些不是用Java编写的使用小端顺序的程序交换数据文件时,就会出现问题。最常见的是使用C编写的程序。某些平台在内部使用大端顺序(Mac,IBM 390),有些使用小端序(Intel)。
C语言默认是小端模式。
如果java 要读取C 写的二进制文件,就要涉及到大小端转换的问题。
java代码测试
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| public static void printSystemInfo() { System.out.println("##########################################"); System.out.println("系统名称:" + System.getProperty("os.name")); System.out.println("系统架构:" + System.getProperty("os.arch")); System.out.println("系统版本:" + System.getProperty("os.version")); System.out.println("##########################################"); System.out.println(""); }
public static Unsafe getUnsafe() throws Exception { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null); return unsafe; }
public static void main(String[] args) throws Exception { printSystemInfo(); try { Unsafe UNSAFE = getUnsafe();
int intVal = 0x1A2B3C4D; System.out.println("原始值:十六进制:" + Integer.toHexString(intVal) + " 对应十进制:" + intVal);
// 分配4个字节的内存 long address = UNSAFE.allocateMemory(4); // 存放int类型的数据,占4个字节 UNSAFE.putInt(address, intVal); byte b = UNSAFE.getByte(address); // 通过getByte方法获取刚才存放的int,取第一个字节 // 如果是大端,存放顺序 —> 1A,2B,3C,4D,取第一位便是0x1A // 如果是小端,存放顺序 —> 4D,3C,2B,1A ,取第一位便是0x4D System.out.println("取到的第一个字节:" + Integer.toHexString(b)); ByteOrder byteOrder; switch (b) { case 0x1A: System.out.println("当前使用:大端序"); byteOrder = ByteOrder.BIG_ENDIAN; break; case 0x4D: System.out.println("当前使用:小端序"); byteOrder = ByteOrder.LITTLE_ENDIAN; break; default: byteOrder = null; } System.out.println(byteOrder); // 这里在X86架构的windows机器上跑,输出结果为: // LITTLE_ENDIAN
// 然后我们重新从内存中读取int int val2 = UNSAFE.getInt(address); System.out.println("重新从内存中读取的值:" + val2); } catch (Exception e) { e.printStackTrace(); } }
|
输出结果
window平台
1 2 3 4 5 6 7 8 9 10 11
| ########################################## 系统名称:Windows 7 系统架构:amd64 系统版本:6.1 ##########################################
原始值:十六进制:1a2b3c4d 对应十进制:439041101 取到的第一个字节:4d 当前使用:小端序 LITTLE_ENDIAN 重新从内存中读取的值:439041101
|
linux平台
1 2 3 4 5 6 7 8 9 10 11
| ########################################## 系统名称:Linux 系统架构:amd64 系统版本:2.6.32-642.el6.x86_64 ##########################################
原始值:十六进制:1a2b3c4d 对应十进制:439041101 取到的第一个字节:4d 当前使用:小端序 LITTLE_ENDIAN 重新从内存中读取的值:439041101
|