大端小端模式
一、介绍
最近一年在使用Android在于单片机打交道,刚开始听说大小端、位运算、高低位觉得很高端,后来慢慢究其本质也就是这么回事。对普通的Android应用开发者来说,使用int、String等数据类型+Json 已经可以满足绝大部分需要,但是对于内存有限的单片机接收Json时,无法像我们一样JsonObject
去方便解析。
所以考虑内存和空间问题,一般和单片机打交道使用的是byte
,byte
是java中最小的单位了,极限优化,一个byte
是8个bit
,虽然bit
只有0和1表示,但在编程的设计场景中已经可以表示很多东西了,比如错误和正确的状态,比如失败和成功的状态。
二、什么是大小端模式
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。
有一张图:
举个例子:
以 unsigned int value = 0x12345678来表示,unsigned char buf[4]存放。
Big-Endian: 低地址存放高位,如下:
高地址
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
低地址
Little-Endian: 低地址存放低位,如下:
高地址
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
--------------
低地址
复制代码
举个例子:
java中的大小端转换
import java.util.Arrays;
class Test {
public static void main(String[] args) {
int a = 10;
byte[] little = intToByteLittle(a);
byte[] big = intToByteBig(a);
System.out.println("little:"+ Arrays.toString(little)); // [10, 0, 0, 0]
System.out.println("big:"+ Arrays.toString(big)); // [0, 0, 0, 10]
}
/**
* 将int转为低字节在前,高字节在后的byte数组(小端)
*
* @param n int
* @return byte[]
*/
public static byte[] intToByteLittle(int n) {
byte[] b = new byte[4];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
b[2] = (byte) (n >> 16 & 0xff);
b[3] = (byte) (n >> 24 & 0xff);
return b;
}
/**
* 将int转为高字节在前,低字节在后的byte数组(大端)
*
* @param n int
* @return byte[]
*/
public static byte[] intToByteBig(int n) {
byte[] b = new byte[4];
b[3] = (byte) (n & 0xff);
b[2] = (byte) (n >> 8 & 0xff);
b[1] = (byte) (n >> 16 & 0xff);
b[0] = (byte) (n >> 24 & 0xff);
return b;
}
}
复制代码
三、为什么要有大小端
这个问题没有定论,就像汽车的方向盘有在左边的,也有在右边的。
四、大小端与什么有关?
编程语言和大小端没有关系,影响大小端的是 编译器
/ CPU
五、Android 是大端还是小端?
上面讲过,CPU和编译器才是影响大端小端的关键,Android系统的碎片化,也说不好Android是大端还是小端。
有必要知道它是大端还是小端吗? 没有必要。
传一个字节会变吗? 不会。
因为在数据转换的过程中就已经指定了是以大端还是小端的规则,相应的,如果传输给其它硬件或者后台,只需要按此规则解析即可。
六、Java 转换大小端的工具类
封装好的工具类,可以通过位运算简单方便的处理我们希望的场景。
import java.util.Arrays;
public class ByteUtils {
/**
* 两个byte[]是否相同
* @param data1
* @param data2
* @return
*/
public static boolean arrayEquals(byte[] data1, byte[] data2) {
return Arrays.equals(data1, data2);
}
/**
* 截取byte[]
* @param data
* @param position
* @param length
* @return
*/
public static byte[] subArray(byte[] data, int position, int length) {
byte[] temp = new byte[length];
System.arraycopy(data, position, temp, 0, length);
return temp;
}
/**
* 解决java中byte输出可能为负数的问题。
* @param b
* @return
*/
public static Integer byteToInteger(Byte b) {
return 0xff & b;
}
/**
* 拼接byte[] 和 byte[]
*
* @param bytes1
* @param bytes2
* @return
*/
public static byte[] byteMerger(byte[] bytes1, byte[] bytes2) {
byte[] bytes3 = new byte[bytes1.length + bytes2.length];
System.arraycopy(bytes1, 0, bytes3, 0, bytes1.length);
System.arraycopy(bytes2, 0, bytes3, bytes1.length, bytes2.length);
return bytes3;
}
/**
* 拼接byte 和 byte[]
*
* @param byte1
* @param bytes2
* @return
*/
public static byte[] byteMerger(byte byte1, byte[] bytes2) {
byte[] bytes3 = new byte[1 + bytes2.length];
bytes3[0] = byte1;
System.arraycopy(bytes2, 0, bytes3, 1, bytes2.length);
return bytes3;
}
/**
* 拼接byte[] 和 byte
*
* @param bytes1
* @param byte2
* @return
*/
public static byte[] byteMerger(byte[] bytes1, byte byte2) {
byte[] bytes3 = new byte[1 + bytes1.length];
System.arraycopy(bytes1, 0, bytes3, 0, bytes1.length);
bytes3[bytes3.length - 1] = byte2;
return bytes3;
}
/**
* 拼接三个数组
*
* @param bt1
* @param bt2
* @param bt3
* @return
*/
public static byte[] byteMerger3(byte[] bt1, byte[] bt2, byte[] bt3) {
byte[] data = new byte[bt1.length + bt2.length + bt3.length];
System.arraycopy(bt1, 0, data, 0, bt1.length);
System.arraycopy(bt2, 0, data, bt1.length, bt2.length);
System.arraycopy(bt3, 0, data, bt1.length + bt2.length, bt3.length);
return data;
}
/**
* Byte[] 与 int 互转
* =============================================================================================
*/
/**
* 将int转为高字节在前,低字节在后的byte数组(大端)
*
* @param n int
* @return byte[]
*/
public static byte[] intToByteBig(int n) {
byte[] b = new byte[4];
b[3] = (byte) (n & 0xff);
b[2] = (byte) (n >> 8 & 0xff);
b[1] = (byte) (n >> 16 & 0xff);
b[0] = (byte) (n >> 24 & 0xff);
return b;
}
/**
* 将int转为低字节在前,高字节在后的byte数组(小端)
*
* @param n int
* @return byte[]
*/
public static byte[] intToByteLittle(int n) {
byte[] b = new byte[4];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
b[2] = (byte) (n >> 16 & 0xff);
b[3] = (byte) (n >> 24 & 0xff);
return b;
}
/**
* byte数组到int的转换(小端)
*
* @param bytes
* @return
*/
public static int bytes2IntLittle(byte[] bytes) {
int int1 = bytes[0] & 0xff;
int int2 = (bytes[1] & 0xff) << 8;
int int3 = (bytes[2] & 0xff) << 16;
int int4 = (bytes[3] & 0xff) << 24;
return int1 | int2 | int3 | int4;
}
/**
* byte数组到int的转换(大端)
*
* @param bytes
* @return
*/
public static int bytes2IntBig(byte[] bytes) {
int int1 = bytes[3] & 0xff;
int int2 = (bytes[2] & 0xff) << 8;
int int3 = (bytes[1] & 0xff) << 16;
int int4 = (bytes[0] & 0xff) << 24;
return int1 | int2 | int3 | int4;
}
/**
* Byte[] 与 short 互转
* =============================================================================================
*/
/**
* 将short转为高字节在前,低字节在后的byte数组(大端)
*
* @param n short
* @return byte[]
*/
public static byte[] shortToByteBig(short n) {
byte[] b = new byte[2];
b[1] = (byte) (n & 0xff);
b[0] = (byte) (n >> 8 & 0xff);
return b;
}
/**
* 将short转为低字节在前,高字节在后的byte数组(小端)
*
* @param n short
* @return byte[]
*/
public static byte[] shortToByteLittle(short n) {
byte[] b = new byte[2];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
return b;
}
/**
* 读取小端byte数组为short
*
* @param b
* @return
*/
public static short byteToShortLittle(byte[] b) {
return (short) (((b[1] << 8) | b[0] & 0xff));
}
/**
* 读取大端byte数组为short
*
* @param b
* @return
*/
public static short byteToShortBig(byte[] b) {
return (short) (((b[0] << 8) | b[1] & 0xff));
}
/**
* Byte[] 与 long 互转
* =============================================================================================
*/
/**
* long类型转byte[] (大端)
*
* @param n
* @return
*/
public static byte[] longToBytesBig(long n) {
byte[] b = new byte[8];
b[7] = (byte) (n & 0xff);
b[6] = (byte) (n >> 8 & 0xff);
b[5] = (byte) (n >> 16 & 0xff);
b[4] = (byte) (n >> 24 & 0xff);
b[3] = (byte) (n >> 32 & 0xff);
b[2] = (byte) (n >> 40 & 0xff);
b[1] = (byte) (n >> 48 & 0xff);
b[0] = (byte) (n >> 56 & 0xff);
return b;
}
/**
* long类型转byte[] (小端)
*
* @param n
* @return
*/
public static byte[] longToBytesLittle(long n) {
byte[] b = new byte[8];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
b[2] = (byte) (n >> 16 & 0xff);
b[3] = (byte) (n >> 24 & 0xff);
b[4] = (byte) (n >> 32 & 0xff);
b[5] = (byte) (n >> 40 & 0xff);
b[6] = (byte) (n >> 48 & 0xff);
b[7] = (byte) (n >> 56 & 0xff);
return b;
}
/**
* byte[]转long类型(小端)
*
* @param array
* @return
*/
public static long bytesToLongLittle(byte[] array) {
return ((((long) array[0] & 0xff) << 0)
| (((long) array[1] & 0xff) << 8)
| (((long) array[2] & 0xff) << 16)
| (((long) array[3] & 0xff) << 24)
| (((long) array[4] & 0xff) << 32)
| (((long) array[5] & 0xff) << 40)
| (((long) array[6] & 0xff) << 48)
| (((long) array[7] & 0xff) << 56));
}
/**
* byte[]转long类型(大端)
*
* @param array
* @return
*/
public static long bytesToLongBig(byte[] array) {
return ((((long) array[0] & 0xff) << 56)
| (((long) array[1] & 0xff) << 48)
| (((long) array[2] & 0xff) << 40)
| (((long) array[3] & 0xff) << 32)
| (((long) array[4] & 0xff) << 24)
| (((long) array[5] & 0xff) << 16)
| (((long) array[6] & 0xff) << 8)
| (((long) array[7] & 0xff) << 0));
}
}
复制代码