近期在寫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的順序都須要是上面描寫敘述的“大端順序”,這樣優點是server發送時能夠調用htonl。htons等函數將字節順序轉換為網絡字節順序,事實上關鍵是server和client要有一個一致的表示規范,看起來似乎網絡字節順序更順眼一些?
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
轉載請保留本說明