需求
單片機通過Socket發送過來類似 { 0xff,0x0c ,0x80...}的byte數組,根據協定分為unsigned char 和signed char兩種類型。需要将int資料轉為兩個byte發送給單片機,或将單片機發來的2個byte轉化為int。
工具程式
/**
* 将兩個byte資料轉化為有符号int
* @param high : 高八位
* @param low : 低八位
* @return
*/
public static int twoByteToSignedInt(byte high,byte low){
return (high << 8) | low;
}
/**
* 将兩個byte資料轉化為無符号int
* @param high : 高八位
* @param low : 低八位
* @return
*/
public static int twoByteToUnsignedInt(byte high,byte low){
return ((high << 8) & 0xffff) | (low & 0x00ff);
}
/**
* 将int轉換為兩個byte
* @param numInt : 實際隻取其中的低16位二進制數
* @return 長度為2的byte數組 ,byte[0]為高8位,byte[1]為低八位
*/
public static byte[] intToTwoByte(int numInt){
byte[] rest = new byte[2];
if(numInt < -32768 || numInt > 32767){
return null;
}
rest[0] = (byte)(numInt >> 8);//高8位
rest[1] = (byte)(numInt & 0x00ff);//低8位
return rest;
}
解釋
- 單片機發送過來的資料有 unsigned char 和 signed char 之分;而 Java 中的 byte(8位)、int(32位) 都是有符号的。
- 計算機裡的數字,不管正負,其底層都是以補碼形式存在的!!
- Java 的二進制采用補碼形式。比如 Java 裡的 Integer.toBinaryString(int) 函數,如果傳入負數,則隻會輸出其補碼形式,傳入正數則輸出原碼二進制數(正數補碼=原碼)。
-
signed char 轉為 Java 的有符号 int
參見函數 twoByteToSignedInt(byte high,byte low) 。由于在單片機中signed char也是以補碼形式存在,是以直接用位操作将兩個byte拼接為一個int即可。
-
unsigned char 轉為 Java 的無符号 int
參見函數 twoByteToUnsignedInt(byte high,byte low) 。那為什麼要按位與0xffff呢?因為byte->int會發生符号擴充,這在轉為有符号int時沒有影響,但在轉為無符号int時,符号擴充會造成數值出現誤差。
具體來說,比如對于一個byte,如果不進行& 0xff,那麼當一個byte會轉換成int時,由于int是32位,而byte隻有8位這時會進行f符号擴充,例如補碼11111111的十進制數為-1,轉換為int時變為1111 1111 1111 1111 1111 1111 1111 1111(補碼)即0xffffffff但是這個數是不對的,這種補位就會造成誤差。和0xff相與後,高24比特就會被清0了,結果就對了。
-
int 轉為 unsigned/signed char
參見intToTwoByte(int numInt)。
直接取int裡的低16位即可。因為無論正負,在單片機裡都是以補碼形式存在,不需要額外轉換。
參考
Java中的Byte轉為無符号的Integer Java中位元組與無符号數之間的轉換 java中無符号類型的解決方案