Little-Endian

LITTLE-ENDIAN(小位元組序、低位元組序),即低位位元組排放在記憶體的低地址端,高位位元組排放在記憶體的高地址端。 與之對應的是:BIG-ENDIAN(大位元組序、高位元組序)

基本介紹

  • 中文名:小端位元組序
  • 外文名:Little-Endian
  • 對應:大位元組序、高位元組序
  • 位元組序:數據在記憶體中的存放順序
位元組序,JAVA,網路位元組,

位元組序

網路位元組順序
位元組序,顧名思義位元組的順序,再多說兩句就是大於一個位元組類型的數據在記憶體中的存放順序(一個位元組的數據當然就無需談順序的問題了)。其實大部分人在實際的開發中都很少會直接和位元組序打交道。唯有在跨平台以及網路程式中位元組序才是一個應該被考慮的問題。
在所有的介紹位元組序的文章中都會提到位元組序分為兩類:Big-Endian和Little-Endian,引用標準的Big-Endian和Little-Endian的定義如下:
a) Little-Endian就是低位位元組排放在記憶體的低地址端,高位位元組排放在記憶體的高地址端。
b) Big-Endian就是高位位元組排放在記憶體的低地址端,低位位元組排放在記憶體的高地址端。
c) 網路位元組序:TCP/IP各層協定將位元組序定義為Big-Endian,因此TCP/IP協定中使用的位元組序通常稱之為網路位元組序。

JAVA

JAVA位元組序
BIG-ENDIAN、LITTLE-ENDIAN跟多位元組類型的數據有關,比如int,short,long型,而對單位元組數據byte卻沒有影響。BIG-ENDIAN就是低位位元組排放在記憶體的高端,高位位元組排放在記憶體的低端。而LITTLE-ENDIAN正好相反。
比如 int a = 0x05060708
在BIG-ENDIAN的情況下存放為:
位元組號 0 1 2 3
數據 05 06 07 08
在LITTLE-ENDIAN的情況下存放為:
位元組號 0 1 2 3
數據 08 07 06 05
BIG-ENDIAN、LITTLE-ENDIAN跟CPU有關,每一種CPU不是BIG-ENDIAN就是LITTLE-ENDIAN。IA架構的CPU中是Little-Endian,而PowerPC 、SPARC和Motorola處理器則是BIG-ENDIAN。這其實就是所謂的主機位元組序。而網路位元組序是指數據在網路上傳輸時是大頭還是小頭的,在Internet的網路位元組序是BIG-ENDIAN。所謂的JAVA位元組序指的是在JAVA虛擬機中多位元組類型數據的存放順序,JAVA位元組序也是BIG-ENDIAN。
所以在用C/C++寫通信程式時,在傳送數據前務必用htonl和htons去把整型和短整型的數據進行從主機位元組序到網路位元組序的轉換,而接收數據後對於整型和短整型數據則必須調用ntohl和ntohs實現從網路位元組序到主機位元組序的轉換。如果通信的一方是JAVA程式、一方是C/C++程式時,則需要在C/C++一側使用以上幾個方法進行位元組序的轉換,而JAVA一側,則不需要做任何處理,因為JAVA位元組序與網路位元組序都是BIG-ENDIAN,只要C/C++一側能正確進行轉換即可(傳送前從主機序到網路序,接收時反變換)。如果通信的雙方都是JAVA,則根本不用考慮位元組序的問題了。
如果網路上全部是PowerPC,SPARC和Motorola CPU的主機那么不會出現任何問題,但由於實際存在大量的IA架構的CPU,所以經常出現數據傳輸錯誤。
文章開頭所提出的問題,就是因為程式運行在X86架構的PC SERVER上,傳送數據的一端是用C實現的,接收一端是用JAVA實現的,而傳送端在傳送數據前未進行從主機位元組序到網路位元組序的轉換,這樣接收端接收到的是LITTLE-ENDIAN的數據,數據解釋自然出錯。
具體數據如下,實際傳送的數據為23578
傳送端傳送數據: 1A 5C
接收端接收到數據後,按BIG-ENDIAN進行解釋具體數據是多少?你們自己去計算並比較吧!
===============================================================================================
Big Endian and Little Endian
談到位元組序的問題,必然牽涉到兩大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列採用big endian方式存儲數據,而x86系列則採用little endian方式存儲數據
為什麼要注意位元組序的問題呢?你可能這么問。當然,如果你寫的程式只在單機環境下面運行,並且不和別人的程式打交道,那么你完全可以忽略位元組序的存在。但是,如果你的程式要跟別人的程式產生互動呢?尤其是當你把你在微機上運算的結果運用到計算機群上去的話。在這裡我想說說兩種語言。C/C++語言編寫的程式里數據存儲順序是跟編譯平台所在的CPU相關的,而JAVA編寫的程式則唯一採用big endian方式來存儲數據。試想,如果你用C/C++語言在x86平台下編寫的程式跟別人的JAVA程式互通時會產生什麼結果?就拿上面的 0x12345678來說,你的程式傳遞給別人的一個數據,將指向0x12345678的指針傳給了JAVA程式,由於JAVA採取big endian方式存儲數據,很自然的它會將你的數據翻譯為0x78563412。什麼?竟然變成另外一個數字了?是的,就是這種後果。因此,在你的C程式傳給JAVA程式之前有必要進行位元組序的轉換工作。
Big-Endian和Little-Endian優缺點
Big-Endian優點:靠首先提取高位位元組,你總是可以由看看在偏移位置為0的位元組來確定這個數字是正數還是負數。你不必知道這個數值有多長,或者你也不必過一些位元組來看這個數值是否含有符號位。這個數值是以它們被列印出來的順序存放的,所以從二進制到十進制的函式特別有效。因而,對於不同要求的機器,在設計存取方式時就會不同。
Little-Endian優點:提取一個,兩個,四個或者更長位元組數據的彙編指令以與其他所有格式相同的方式進行:首先在偏移地址為0的地方提取最低位的位元組,因為地址偏移和位元組數是一對一的關係,多重精度的數學函式就相對地容易寫了。
如果你增加數字的值,你可能在左邊增加數字(高位非指數函式需要更多的數字)。因此,經常需要增加兩位數字並移動存儲器里所有Big-endian順序的數字,把所有數向右移,這會增加計算機的工作量。不過,使用Little- Endian的存儲器中不重要的位元組可以存在它原來的位置,新的數可以存在它的右邊的高位地址里。這就意味著計算機中的某些計算可以變得更加簡單和快速。

網路位元組

無獨有偶,所有網路協定也都是採用big endian的方式來傳輸數據的。所以有時我們也會把big endian方式稱之為網路位元組序。當兩台採用不同位元組序的主機通信時,在傳送數據之前都必須經過位元組序的轉換成為網路位元組序後再進行傳輸。ANSI C中提供了四個轉換位元組序的宏。
========================================================================================================
/**
* 通信格式轉換
*
* Java和一些windows程式語言如c、c++、delphi所寫的網路程式進行通訊時,需要進行相應的轉換
* 高、低位元組之間的轉換
* windows的位元組序為低位元組開頭
* linux,unix的位元組序為高位元組開頭
* java則無論平台變化,都是高位元組開頭
*/
public class FormatTransfer {
/**
* 將int轉為低位元組在前,高位元組在後的byte數組
* @param n int
* @return byte[]
*/
public static byte[] toLH(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[] toHH(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;
}
/**
* 將short轉為低位元組在前,高位元組在後的byte數組
* @param n short
* @return byte[]
*/
public static byte[] toLH(short n) {
byte[] b = new byte[2];
b[0] = (byte) (n & 0xff);
b[1] = (byte) (n >> 8 & 0xff);
return b;
}
/**
* 將short轉為高位元組在前,低位元組在後的byte數組
* @param n short
* @return byte[]
*/
public static byte[] toHH(short n) {
byte[] b = new byte[2];
b[1] = (byte) (n & 0xff);
b[0] = (byte) (n >> 8 & 0xff);
return b;
}
/**
* 將將int轉為高位元組在前,低位元組在後的byte數組
public static byte[] toHH(int number) {
int temp = number;
byte[] b = new byte[4];
for (int i = b.length - 1; i > -1; i--) {
b = new Integer(temp & 0xff).byteValue();
temp = temp >> 8;
}
return b;
}
public static byte[] IntToByteArray(int i) {
byte[] abyte0 = new byte[4];
abyte0[3] = (byte) (0xff & i);
abyte0[2] = (byte) ((0xff00 & i) >> 8);
abyte0[1] = (byte) ((0xff0000 & i) >> 16);
abyte0[0] = (byte) ((0xff000000 & i) >> 24);
return abyte0;
}
*/
/**
* 將float轉為低位元組在前,高位元組在後的byte數組
*/
public static byte[] toLH(float f) {
return toLH(Float.floatToRawIntBits(f));
}
/**
* 將float轉為高位元組在前,低位元組在後的byte數組
*/
public static byte[] toHH(float f) {
return toHH(Float.floatToRawIntBits(f));
}
/**
* 將String轉為byte數組
*/
public static byte[] stringToBytes(String s, int length) {
while (s.getBytes().length < length) {
s += " ";
}
return s.getBytes();
}
/**
* 將位元組數組轉換為String
* @param b byte[]
* @return String
*/
public static String bytesToString(byte[] b) {
StringBuffer result = new StringBuffer("");
int length = b.length;
for (int i=0; i<length; i++) {
result.append((char)(b & 0xff));
}
return result.toString();
}
/**
* 將字元串轉換為byte數組
* @param s String
* @return byte[]
*/
public static byte[] stringToBytes(String s) {
return s.getBytes();
}
/**
* 將高位元組數組轉換為int
* @param b byte[]
* @return int
*/
public static int hBytesToInt(byte[] b) {
int s = 0;
for (int i = 0; i < 3; i++) {
if (b[i] >= 0) {
s = s + b[i];
} else {
s = s + 256 + b[i];
}
s = s * 256;
}
if (b[3] >= 0) {
s = s + b[3];
} else {
s = s + 256 + b[3];
}
return s;
}
/**
* 將低位元組數組轉換為int
* @param b byte[]
* @return int
*/
public static int lBytesToInt(byte[] b) {
int s = 0;
for (int i = 0; i < 3; i++) {
if (b[3-i] >= 0) {
s = s + b[3-i];
} else {
s = s + 256 + b[3-i];
}
s = s * 256;
}
if (b[0] >= 0) {
s = s + b[0];
} else {
s = s + 256 + b[0];
}
return s;
}
/**
* 高位元組數組到short的轉換
* @param b byte[]
* @return short
*/
public static short hBytesToShort(byte[] b) {
int s = 0;
if (b[0] >= 0) {
s = s + b[0];
} else {
s = s + 256 + b[0];
}
s = s * 256;
if (b[1] >= 0) {
s = s + b[1];
} else {
s = s + 256 + b[1];
}
short result = (short)s;
return result;
}
/**
* 低位元組數組到short的轉換
* @param b byte[]
* @return short
*/
public static short lBytesToShort(byte[] b) {
int s = 0;
if (b[1] >= 0) {
s = s + b[1];
} else {
s = s + 256 + b[1];
}
s = s * 256;
if (b[0] >= 0) {
s = s + b[0];
} else {
s = s + 256 + b[0];
}
short result = (short)s;
return result;
}
/**
* 高位元組數組轉換為float
* @param b byte[]
* @return float
*/
public static float hBytesToFloat(byte[] b) {
int i = 0;
Float F = new Float(0.0);
i = ((((b[0]&0xff)<<8 | (b[1]&0xff))<<8) | (b[2]&0xff))<<8 | (b[3]&0xff);
return F.intBitsToFloat(i);
}
/**
* 低位元組數組轉換為float
* @param b byte[]
* @return float
*/
public static float lBytesToFloat(byte[] b) {
int i = 0;
Float F = new Float(0.0);
i = ((((b[3]&0xff)<<8 | (b[2]&0xff))<<8) | (b[1]&0xff))<<8 | (b[0]&0xff);
return F.intBitsToFloat(i);
}
/**
* 將byte數組中的元素倒序排列
*/
public static byte[] bytesReverseOrder(byte[] b) {
int length = b.length;
byte[] result = new byte[length];
for(int i=0; i<length; i++) {
result[length-i-1] = b;
}
return result;
}
/**
* 列印byte數組
*/
public static void printBytes(byte[] bb) {
int length = bb.length;
for (int i=0; i<length; i++) {
System.out.print(bb + " ");
}
System.out.println("");
}
public static void logBytes(byte[] bb) {
int length = bb.length;
String ut = "";
for (int i=0; i<length; i++) {
ut = out + bb + " ";
}
}
/**
* 將int類型的值轉換為位元組序顛倒過來對應的int值
* @param i int
* @return int
*/
public static int reverseInt(int i) {
int result = FormatTransfer.hBytesToInt(FormatTransfer.toLH(i));
return result;
}
/**
* 將short類型的值轉換為位元組序顛倒過來對應的short值
* @param s short
* @return short
*/
public static short reverseShort(short s) {
short result = FormatTransfer.hBytesToShort(FormatTransfer.toLH(s));
return result;
}
/**
* 將float類型的值轉換為位元組序顛倒過來對應的float值
* @param f float
* @return float
*/
public static float reverseFloat(float f) {
float result = FormatTransfer.hBytesToFloat(FormatTransfer.toLH(f));
return result;
}
}

相關詞條

熱門詞條

聯絡我們