最近在写C++ socket和java socket之间的通信程序,涉及到整数浮点数的传输,需要从字节数组还原数据,查了一些资料,总结如下
1. 整数和浮点数的机器表示
在机器内部,不论是一个整数还是浮点数,都是以一个二进制串的形式存储。
整数可能是原码,补码表示,浮点数有阶码尾数两部分构成,无论怎样都是一个二进制串,但是这个二进制串如何表示不同的机器可能采取不同的方案。
关于浮点数:
一个机器上的32位浮点数的二进制串在另一个机器把它作为32位浮点数解释时可能得到不同的值,这样不同机器上进行网络传输的时候,大概就只能用传字符串的方式了,不过幸好,IEEE 754规范标准化了浮点数的表示形式,遵从这个标准的不同编程语言里只要遵从这个标准,那么某个浮点数的32位二进制串都是一样的,,,和CPU无关,和语言无关
关于整数 :
单个字节的整型值就是一个字节;占用多个字节的整数,其表示有所区别,有所谓的小端法,大端法,具体表示可以看下面的图。
2. 小端法、大端法和主机字节顺序、网络字节顺序
小端法和大端法如图所示
网络字节序就是大端顺序,因为TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。
主机字节顺序就是指相对于网络传输是的字节顺序的主机上的字节顺序,有大端表示法,小端表示法。
3. 下面给出java中的基本数据类型和字节数组byte[]之间的转换代码
本文中byte[]的顺序按照“大端顺序”,这句话的意思是说对于整数0x11223344
byte[0]保存0x11,byte[1]保存0x22,byte[2]保存0x33,byte[3]保存0x44
采用这种“大端顺序”,由byte[]转int,或由int转byte[],这里面byte的顺序都需要是上面描述的“大端顺序”,这样好处是服务器发送时可以调用htonl,htons等函数将字节顺序转换为网络字节顺序,其实关键是服务器和客户端要有一个一致的表示规范,看起来似乎网络字节顺序更顺眼一些?
Java对于各种基本类型的长度做了规定,所以对应byte数组的长度也固定,和机器无关。
下面是char,short,int,float,long,double转换的代码,核心是利用位操作,取出某个字节中的8个位,进行转换。
很大程度上参考了http://tjmljw.iteye.com/blog/1767716一文中的实现(该文采用的是“小端顺序”的byte数组,我用的是“大端顺序”)。
import java.nio.ByteOrder; public class ByteArrayConveter { // char转换为byte[2]数组 public static byte[] getByteArray(char c) { byte[] b = new byte[2]; b[0] = (byte) ((c & 0xff00) >> 8); b[1] = (byte) (c & 0x00ff); return b; } // 从byte数组的index处的连续两个字节获得一个char public static char getChar(byte[] arr, int index) { return (char) (0xff00 & arr[index] << 8 | (0xff & arr[index + 1])); } // short转换为byte[2]数组 public static byte[] getByteArray(short s) { byte[] b = new byte[2]; b[0] = (byte) ((s & 0xff00) >> 8); b[1] = (byte) (s & 0x00ff); return b; } // 从byte数组的index处的连续两个字节获得一个short public static short getShort(byte[] arr, int index) { return (short) (0xff00 & arr[index] << 8 | (0xff & arr[index + 1])); } // int转换为byte[4]数组 public static byte[] getByteArray(int i) { byte[] b = new byte[4]; b[0] = (byte) ((i & 0xff000000) >> 24); b[1] = (byte) ((i & 0x00ff0000) >> 16); b[2] = (byte) ((i & 0x0000ff00) >> 8); b[3] = (byte) (i & 0x000000ff); return b; } // 从byte数组的index处的连续4个字节获得一个int public static int getInt(byte[] arr, int index) { return (0xff000000 & (arr[index+0] << 24)) | (0x00ff0000 & (arr[index+1] << 16)) | (0x0000ff00 & (arr[index+2] << 8)) | (0x000000ff & arr[index+3]); } // float转换为byte[4]数组 public static byte[] getByteArray(float f) { int intbits = Float.floatToIntBits(f);//将float里面的二进制串解释为int整数 return getByteArray(intbits); } // 从byte数组的index处的连续4个字节获得一个float public static float getFloat(byte[] arr, int index) { return Float.intBitsToFloat(getInt(arr, index)); } // long转换为byte[8]数组 public static byte[] getByteArray(long l) { byte b[] = new byte[8]; b[0] = (byte) (0xff & (l >> 56)); b[1] = (byte) (0xff & (l >> 48)); b[2] = (byte) (0xff & (l >> 40)); b[3] = (byte) (0xff & (l >> 32)); b[4] = (byte) (0xff & (l >> 24)); b[5] = (byte) (0xff & (l >> 16)); b[6] = (byte) (0xff & (l >> 8)); b[7] = (byte) (0xff & l); return b; } // 从byte数组的index处的连续8个字节获得一个long public static long getLong(byte[] arr, int index) { return (0xff00000000000000L & ((long)arr[index+0] << 56)) | (0x00ff000000000000L & ((long)arr[index+1] << 48)) | (0x0000ff0000000000L & ((long)arr[index+2] << 40)) | (0x000000ff00000000L & ((long)arr[index+3] << 32)) | (0x00000000ff000000L & ((long)arr[index+4] << 24)) | (0x0000000000ff0000L & ((long)arr[index+5] << 16)) | (0x000000000000ff00L & ((long)arr[index+6] << 8)) | (0x00000000000000ffL & (long)arr[index+7]); } // double转换为byte[8]数组 public static byte[] getByteArray(double d) { long longbits = Double.doubleToLongBits(d); return getByteArray(longbits); } // 从byte数组的index处的连续8个字节获得一个double public static double getDouble(byte[] arr, int index) { return Double.longBitsToDouble(getLong(arr, index)); } public static void main(String[] args) { System.out.println(ByteOrder.nativeOrder()); if(args.length < 1){ System.out.println("enter 'char' test method about char"); System.out.println("enter 'short' test method about short"); System.out.println("enter 'int' test method about int"); System.out.println("enter 'float' test method about float"); System.out.println("enter 'long' test method about long"); System.out.println("enter 'double' test method about double"); return; } if(args[0].equals("char")){ char c = '\u0000'; while( c < '\uffff'){ System.out.println(getChar(getByteArray(c),0)); c++; } }else if(args[0].equals("short")){ short s = Short.MIN_VALUE; while( s < Short.MAX_VALUE){ System.out.println(getShort(getByteArray(s), 0)); s++; } }else if(args[0].equals("int")){ int i = Integer.MIN_VALUE; while( i < Integer.MAX_VALUE){ System.out.println(getInt(getByteArray(i), 0)); i++; } }else if(args[0].equals("float")){ float f = Float.MIN_VALUE; while(f < Float.MAX_VALUE){ System.out.println(getFloat(getByteArray(f), 0)); f+=1.1111f; } }else if(args[0].equals("long")){ long l = Long.MIN_VALUE; while(l < Long.MAX_VALUE){ System.out.println(getLong(getByteArray(l), 0)); l++; } }else if(args[0].equals("double")){ double d = Double.MIN_VALUE; while(d < Double.MAX_VALUE){ System.out.println(getDouble(getByteArray(d), 0)); d+=1.111D; } } } }
说明:
本文由giantpoplar发表于CSDN文章地址 http://write.blog.csdn.net/postedit/47657333
转载请保留本说明