1

符号なし 32 ビット整数のリトル エンディアン エンコーディングである 4 バイトを読み取り、その値を Java int に割り当てたい

(はい、実際には「long」を使用しますが、この場合、unsigned 値が 2 の補数表記で signed int をオーバーフローするほど大きくなることは決してないことを「知っています」。 )。

問題の 4 バイトは、値「216」をリトルエンディアン スタイルでエンコードします。

0xD8000000

基本的には、次のビット パターンを Java int に詰め込むだけです。

0x000000D8

次の単純なコードでそれを行う必要があります...そして最初の 3 つの '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 であるため、最上位ビットが 1 であるため、これは 2 の補数表記の負の数 (-40) です。 、-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つのメソッド呼び出しを使用しています。

ありがとう!デビッド。

4

1 に答える 1

6

上位ビットが0 に設定されて& 0xffいることを確認するために、バイトから int への昇格を含めるだけです。

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」は不要ですが、一貫性が高く保たれます。)

于 2010-09-30T16:37:45.333 に答える