2010-09-30 23 views
1

我想讀取4個字節,它是一個無符號的32位整數的小端編碼,並將該值賦值給Java int只需使用按位運算符就可以將一個無符號整數的4個小端順序字節分配給Java基元嗎?

(是的,實際上我會用'long',但是在這種情況下,我'知道'無符號值永遠不會這麼大,它會溢出一個有符號整數在補碼符號,它適合我的插圖使用一個int)。

有問題的4個字節編碼值 '216' little-endian的風格:

0xD8000000 

,基本上我只需要下面的位模式塞進Java int的:

0x000000D8 

的以下簡單的代碼應該做到這一點......併爲前三個'0x00'字節成功:

byte b1 = din.readByte(); 
byte b2 = din.readByte(); 
byte b3 = din.readByte(); 
byte b4 = din.readByte(); 
int s = 0; 
s = s | b4; 
s = (s << 8); 
s = s | b3; 
s = (s << 8); 
s = s | b2; 
s = (s << 8); 
s = s | b1; 
return s; 

然而,它搞砸了在:

s = s | b1; 

...因爲B1的位是1101 1000,這是二進制補碼負數(-40),因爲最顯著位是1 。當Java在評估位運算符或運算符|之前將b1擴展爲int時,-40被編碼爲0xFFFFFFD8,這固定了我們天真的假設,即加寬int的前3個字節將爲0。

所以我的策略擱淺。但是我應該怎麼做呢?甚至有可能使用原始操作符來解決這個問題(請給出解決方案),還是必須訴諸類庫? (我在正常的編碼中並沒有直接使用比特和字節,所以我缺少這種習慣用法,因爲它似乎應該是'每天'的代碼)。

至於類庫的方法,下面的代碼片段得到正確的結果:

ByteBuffer b = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).put((byte) 0xD8).put((byte) 0x00).put((byte) 0x00).put((byte) 0x00); 
b.flip(); 
int s = b.getInt(); 

...這是罰款的可讀性,但使用8個的方法調用,我寧願免除。

謝謝! David。

回答

6

就包括& 0xff每個字節爲int的推廣,以確保頂位設置爲0:

byte b1 = din.readByte(); 
byte b2 = din.readByte(); 
byte b3 = din.readByte(); 
byte b4 = din.readByte(); 
int s = 0; 
s = s | (b4 & 0xff); 
s = (s << 8); 
s = s | (b3 & 0xff); 
s = (s << 8); 
s = s | (b2 & 0xff); 
s = (s << 8); 
s = s | (b1 & 0xff); 
return s; 

或者更簡潔:

byte b1 = din.readByte(); 
byte b2 = din.readByte(); 
byte b3 = din.readByte(); 
byte b4 = din.readByte(); 
return ((b4 & 0xff) << 24) 
    | ((b3 & 0xff) << 16) 
    | ((b2 & 0xff) << 8) 
    | ((b1 & 0xff) << 0); 

(顯然「左移0」是不必要的,但它保持了更高的一致性。)

+1

得看那個標誌擴展名。 – dty 2010-09-30 16:43:28

+0

啊,我在狩獵期間看過那種東西,卻沒有花時間去執行我腦海中的代碼。但現在你說出來了,這很有道理,我將不會被未來的簡單包裝嚇倒!謝謝。 – 2010-09-30 17:10:48

相關問題