2012-05-29 7 views
7

Muszę konwertować bajty na podpisane/unsigned int lub krótkie.Konwertuj z 2 lub 4 bajty na podpisane/unsigned krótkie/int

Poniższe metody są prawidłowe? Który jest podpisany, a który niepodpisany?

kolejność bajtów: LITTLE_ENDIAN

public static int convertTwoBytesToInt1(byte b1, byte b2) { 
    return (int) ((b2 << 8) | (b1 & 0xFF)); 
} 

VS.

public static int convertTwoBytesToInt2(byte b1, byte b2) { 
    return (int) (((b2 & 0xFF) << 8) | (b1 & 0xFF)); 
} 

i

public static int convertFourBytesToInt1(byte b1, byte b2, byte b3, byte b4){ 
    return (int) ((b4<<24)+(b3<<16)+(b2<<8)+b1); 
} 

VS.

public static int convertFourBytesToInt2(byte b1, byte b2, byte b3, byte b4){ 
    return (int) (((b4 & 0xFF) << 24) | ((b3 & 0xFF) << 16) | ((b2 & 0xFF) << 8) | (b1 & 0xFF)); 
} 

Jestem zainteresowany tylko w tych formach konwersji. Dzięki!

+1

użyłbym ByteBuffer jak to może być dużo bardziej wydajny i można po prostu ustawić '.order (ByteOrder.LITTLE_ENDIAN)' –

Odpowiedz

6

Pierwsza metoda (convertXXXToInt1()) dla każdej pary jest podpisana, a druga (convertXXXToInt2()) jest niepodpisana.

Jednak Java int jest zawsze podpisane, więc jeżeli najwyższy bit b4 jest ustawiony, wynik convertFourBytesToInt2() będzie ujemny, mimo to ma być „unsigned” wersja.

Załóżmy, że wartość byte, b2 wynosi -1, lub 0xFF w systemie szesnastkowym. Operator << spowoduje, że zostanie "wypromowany" na typ int o wartości -1 lub 0xFFFFFFFF. Po przesunięciu 8 bitów będzie to 0xFFFFFF00, a po przesunięciu 24 bajtów będzie to 0xFF000000.

Jeśli jednak zastosujesz bitowy operator &, bity wyższego rzędu zostaną ustawione na zero. Spowoduje to odrzucenie informacji o znaku. Oto pierwsze kroki obu spraw, opracowane bardziej szczegółowo.

Podpisano:

byte b2 = -1; // 0xFF 
int i2 = b2; // 0xFFFFFFFF 
int n = i2 << 8; // 0x0xFFFFFF00 

Niepodpisana:

byte b2 = -1; // 0xFF 
int i2 = b2 & 0xFF; // 0x000000FF 
int n = i2 << 8; // 0x0000FF00 
+0

Na convertFourBytesToInt1 b1 nie ma & 0xFF ... Więc jeśli nie umieścić to nie robi różnicy? Nadal jest podpisany int? – blackwolf

+0

@blackwolf Właściwie to robi różnicę, ponieważ łączysz bajty z operatorem '+'. Nie zauważyłem tego wcześniej, ponieważ inni używają operatora '|', który jest preferowany do manipulacji bitem. Wyrażenie powinno mieć postać '(int) ((b4 << 24) | ((b3 i 0xFF) << 16) | ((b2 i 0xFF) << 8) | (b1 i 0xFF))' – erickson

1

Jest problem z 4-bajtowy niepodpisane konwersji, ponieważ nie pasuje do wew. Poniższe podprogramy działają poprawnie.

public class IntegerConversion 
{ 
    public static int convertTwoBytesToInt1 (byte b1, byte b2)  // signed 
    { 
    return (b2 << 8) | (b1 & 0xFF); 
    } 

    public static int convertFourBytesToInt1 (byte b1, byte b2, byte b3, byte b4) 
    { 
    return (b4 << 24) | (b3 & 0xFF) << 16 | (b2 & 0xFF) << 8 | (b1 & 0xFF); 
    } 

    public static int convertTwoBytesToInt2 (byte b1, byte b2)  // unsigned 
    { 
    return (b2 & 0xFF) << 8 | (b1 & 0xFF); 
    } 

    public static long convertFourBytesToInt2 (byte b1, byte b2, byte b3, byte b4) 
    { 
    return (long) (b4 & 0xFF) << 24 | (b3 & 0xFF) << 16 | (b2 & 0xFF) << 8 | (b1 & 0xFF); 
    } 

    public static void main (String[] args) 
    { 
    byte b1 = (byte) 0xFF; 
    byte b2 = (byte) 0xFF; 
    byte b3 = (byte) 0xFF; 
    byte b4 = (byte) 0xFF; 

    System.out.printf ("%,14d%n", convertTwoBytesToInt1 (b1, b2)); 
    System.out.printf ("%,14d%n", convertTwoBytesToInt2 (b1, b2)); 

    System.out.printf ("%,14d%n", convertFourBytesToInt1 (b1, b2, b3, b4)); 
    System.out.printf ("%,14d%n", convertFourBytesToInt2 (b1, b2, b3, b4)); 
    } 
} 
+0

Co to jest b1 & 0xFF dla? – ScottF

+0

@ScottF - aby zapobiec wartościom ujemnym. – dmolony