今天搜到的一个知识,分享 一下。
1.故事的起源
“endian”这个词出自《格列佛游记》 。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。
我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”(我宁可称为“大字节序”与“小字节序”,不受“尾”字的干扰)。
2.正文
谈到字节序的问题,必然牵涉到两大CPU派系。那就是Motorola的PowerPC系列CPU和 Intel的x86系列CPU。PowerPC系列采用big endian方式存储数据 ,而x86系列则采用little endian方式存储数据。那么究竟什么是big endian,什么又是little endian呢?
对于单一的字节(a byte ),大部分处理器 以相同的顺序处理位元 (bit),因此单字节的存放方法和传输方式一般相同。
对于多字节数据,如整数(32位机中一般占4字节),在不同的处理器的存放方式主要有两种,以内存中0x0A0B0C0D的存放方式为例,分别有以下几种方式:
大端序 (英:big-endian)或称大尾序 。
地址增长方向 → | |||||
... | 0x0A | 0x0B | 0x0C | 0x0D | ... |
示例中,最高有效位 (MSB, Most Significant Byte)是0x0A 存储在最低的内存地址处。下一个字节0x0B 存在后面的地址处。正类似于十六进制字节从左到右的阅读顺序。
地址增长方向 → | |||||
... | 0x0A0B | 0x0C0D | ... |
最高的16bit单元0x0A0B 存储在低位。
小端序 (英:little-endian)或称小尾序 。
地址增长方向 → | |||||
... | 0x0D | 0x0C | 0x0B | 0x0A | ... |
最低有效位 (LSB,Least Significant Byte)是0x0D 存储在最低的内存地址处。后面字节依次存在后面的地址处。
地址增长方向 → | |||||
... | 0x0C0D | 0x0A0B | ... |
最低的16bit单元0x0C0D 存储在低位。
当更改地址的增长方向,使之由右至左时,表格更具有可阅读性。
← 地址增长方向 | |||||
... | 0x0A | 0x0B | 0x0C | 0x0D | ... |
最低有效位(LSB)是0x0D 存储在最低的内存地址处。后面字节依次存在后面的地址处。
← 地址增长方向 | |||||
... | 0x0A0B | 0x0C0D | ... |
最低的16bit单元0x0C0D 存储在低位。
从上面两图可以看出,采用big endian方式存储数据是符合我们人类的思维习惯的。
混合序 (英:middle-endian)具有更复杂的顺序。以PDP-11 为例,0x0A0B0C0D被存储为:
地址增长方向 → | |||||
... | 0x0B | 0x0A | 0x0D | 0x0C | ... |
可以看作最高的16bit位和低位以大端序存储,但16bit内部以小端存储。
3.下面附一转载的代码 ,可实现两种字序下byte[]数组与int之间的互相转换:
//工具类 package lab.sodino.endian; /** * @author Sodino E-mail:[email protected] * @version Time 2011-1-14 下午03:19:12 */ public class EndianUtil { /** * 将字节数组转为 Java 中的 int 数值 * * @param bys * 字节数组 * @param start * 需要转换的起始索引点 * @param len * 需要转换的字节长度 * @param isBigEndian * 是否是 BE(true -- BE 序,false -- LE 序) * @return */ public static Object Bytes2NumWrapper(byte[] data, int start, int len, Class wrapper, boolean isBigEndian) { Object obj = null; int wrapperSize = 0; int move = 0; if (wrapper == Byte.class) { byte tmp = 0; wrapperSize = Byte.SIZE; move = Byte.SIZE / Byte.SIZE; for (int i = start, k = start + len % (wrapperSize / Byte.SIZE + 1); i < k; i++) { // ((i - start) % move))亦可只写为(i - start) tmp |= (data[i] & 0xff) << ((isBigEndian ? (k - i - 1) : ((i - start) % move)) * Byte.SIZE); } obj = new Byte(tmp); } else if (wrapper == Short.class) { short tmp = 0; wrapperSize = Short.SIZE; move = Short.SIZE / Byte.SIZE; for (int i = start, k = start + len % (wrapperSize / Byte.SIZE + 1); i < k; i++) { // ((i - start) % move))亦可只写为(i - start) tmp |= (data[i] & 0xff) << ((isBigEndian ? (k - i - 1) : ((i - start) % move)) * Byte.SIZE); } obj = new Short(tmp); } else if (wrapper == Integer.class) { int tmp = 0; wrapperSize = Integer.SIZE; move = Integer.SIZE / Byte.SIZE; for (int i = start, k = start + len % (wrapperSize / Byte.SIZE + 1); i < k; i++) { // ((i - start) % move))亦可只写为(i - start) tmp |= (data[i] & 0xff) << ((isBigEndian ? (k - i - 1) : ((i - start) % move)) * Byte.SIZE); } System.out.println("tmp=" + Integer.toHexString(tmp) + "/n----test End"); obj = new Integer(tmp); } else if (wrapper == Long.class) { long tmp = 0; wrapperSize = Long.SIZE; move = Long.SIZE / Byte.SIZE; for (int i = start, k = start + len % (wrapperSize / Byte.SIZE + 1); i < k; i++) { // 注意此处需得标明 0xff为l(long)型 // ((i - start) % move))亦可只写为(i - start) tmp |= (data[i] & 0xffl) << ((isBigEndian ? (k - i - 1) : ((i - start) % move)) * Byte.SIZE); } obj = new Long(tmp); } return obj; } /** * @param num * 指定的整型数 * @param isBigEndian * 是否是大字节序。 */ public static byte[] NumWrapper2Bytes(Object num, boolean isBigEndian) { byte[] data = null; int wrapperSize = 0; if (num instanceof Byte) { data = new byte[1]; data[0] = ((Byte) num).byteValue(); } else if (num instanceof Short) { wrapperSize = Short.SIZE; short tmp = ((Short) num).shortValue(); data = new byte[wrapperSize / Byte.SIZE]; for (int i = 0; i < data.length; i++) { data[i] = (byte) (tmp >>> ((isBigEndian ? (data.length - i - 1) : i)) * Byte.SIZE); } } else if (num instanceof Integer) { wrapperSize = Integer.SIZE; int tmp = ((Integer) num).intValue(); data = new byte[wrapperSize / Byte.SIZE]; for (int i = 0; i < data.length; i++) { data[i] = (byte) (tmp >>> ((isBigEndian ? (data.length - i - 1) : i)) * Byte.SIZE); } } else if (num instanceof Long) { wrapperSize = Long.SIZE; long tmp = ((Long) num).longValue(); data = new byte[wrapperSize / Byte.SIZE]; for (int i = 0; i < data.length; i++) { data[i] = (byte) (tmp >>> ((isBigEndian ? (data.length - i - 1) : i)) * Byte.SIZE); } } return data; } } //测试类 package lab.sodino.endian; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; /** * @author Sodino E-mail:[email protected] * @version Time�?011-1-14 下午05:30:46 */ public class EndianMain { public static void main(String[] args) { testByte(); testShort(); testInteger(); testLong(); } public static void testByte() { byte[] data = EndianUtil.NumWrapper2Bytes(new Byte((byte) 0x01), false); System.out.print("data.length=" + data.length + " Content:"); for (int i = 0; i < data.length; i++) { System.out.print(data[i] + " "); } System.out.println("/nEnd NumWrapper2Bytes"); Object obj = EndianUtil.Bytes2NumWrapper(data, 0, data.length, Byte.class, false); byte num = ((Byte) obj).byteValue(); System.out.println(Integer.toHexString(num)); System.out.println("End Bytes2NumWrapper"); } public static void testShort() { byte[] data = EndianUtil.NumWrapper2Bytes(new Short((short) 0x0102), false); System.out.print("data.length=" + data.length + " Content:"); for (int i = 0; i < data.length; i++) { System.out.print(data[i] + " "); } System.out.println("/nEnd NumWrapper2Bytes"); Object obj = EndianUtil.Bytes2NumWrapper(data, 0, data.length, Short.class, false); short num = ((Short) obj).shortValue(); System.out.println("Hex:0x" + Integer.toHexString(num)); System.out.println("End Bytes2NumWrapper"); } public static void testInteger() { byte[] data = EndianUtil.NumWrapper2Bytes(new Integer(0x01020304), false); System.out.print("data.length=" + data.length + " Content:"); for (int i = 0; i < data.length; i++) { System.out.print(data[i] + " "); } System.out.println("/nEnd NumWrapper2Bytes"); Object obj = EndianUtil.Bytes2NumWrapper(data, 0, data.length, Integer.class, false); int num = ((Integer) obj).intValue(); System.out.println("Hex:0x" + Integer.toHexString(num)); System.out.println("End Bytes2NumWrapper"); } public static void testLong() { byte[] data = EndianUtil.NumWrapper2Bytes( new Long(0x0102030405060708l), false); System.out.print("data.length=" + data.length + " Content:"); for (int i = 0; i < data.length; i++) { System.out.print(data[i] + " "); } System.out.println("/nEnd NumWrapper2Bytes"); Object obj = EndianUtil.Bytes2NumWrapper(data, 0, data.length, Long.class, false); long num = ((Long) obj).longValue(); System.out.println("Hex:0x" + Long.toHexString(num)); System.out.println("End Bytes2NumWrapper"); } }
本文内容归CSDN博客博主Sodino 所有
转载请注明出处: http://blog.csdn.net/sodino/archive/2010/12/21/6088073.aspx