大端小端模式

大端小端模式

一、介绍

最近一年在使用Android在于单片机打交道,刚开始听说大小端、位运算、高低位觉得很高端,后来慢慢究其本质也就是这么回事。对普通的Android应用开发者来说,使用int、String等数据类型+Json 已经可以满足绝大部分需要,但是对于内存有限的单片机接收Json时,无法像我们一样JsonObject去方便解析。

所以考虑内存和空间问题,一般和单片机打交道使用的是bytebyte是java中最小的单位了,极限优化,一个byte是8个bit,虽然bit只有0和1表示,但在编程的设计场景中已经可以表示很多东西了,比如错误和正确的状态,比如失败和成功的状态。

二、什么是大小端模式

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。

有一张图:

20190825193434559.png

举个例子:

以 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));

}

}

复制代码

猜你喜欢

转载自juejin.im/post/6987999503978758151