0xff << nはJavaで何をしますか?

Sep 17 2020

Inputstreamから、最初の4バイトを読み取り、これらをパックして、この場合はストリームのサイズ/長さに関する情報を取得しました。

そのために、別のプロジェクトからコピーした次のコード(例1)を使用します

例1:バイト配列を使用します。値はInputStreamから長さ4のin_buf []という名前の配列に読み込まれ、値は{0,0,12,26}です。

例1

int size = (((in_buf[0] & 0xff) << 24) | ((in_buf[1] & 0xff) << 16) |
            ((in_buf[2] & 0xff) << 8) | (in_buf[3] & 0xff)); // result its 3098

その結果、私はサイズの値になります、いいですが..

ここで何が起こるかを説明する必要があり、すべての関数を分割して何が起こるかを確認し、デバッグしようとすると、次の結果になります

    int byte1 = ((in_buf[0] & 0xff) << 24); // result 0
    int byte2 = ((in_buf[1] & 0xff) << 16); // result 0
    int byte3 = ((in_buf[2] & 0xff) << 8);  // result 3072
    int byte4 = (in_buf[3] & 0xff);         // result 26

次に、例1から、サイズの結果は0 + 0 + 3072 + 26の合計であると推測しますが、ここでは正確に何が起こりますか(値12と26のみ)?またはそれが行われた操作?

このようなもの ?

0000 0000 0000 1100  //12  << 8
0000 1100 0000 0000  // result after << 8

そして、なぜマスクと0xffを使用する必要があるのですか?

cuz int byte3a =(in_buf [3]&0xff)をデバッグすると、結果はint byte3b = in_buf [3]と同じではありません。したがって、12、*ここでin_buf [3] = 12の値; デバッグ結果から画像を追加します。

何が起こるか、これをin_buf [3]&0xffのようにしますか?

  0000 0000 0000 1100 (12)
& 0000 0000 1111 1111 (0xff)
  -------------------
  0000 0000 1111 0011 ?

Eclipseのスクリーンショット

回答

4 Sweeper Sep 17 2020 at 18:27

これらのようなもの?

はい。ただし、オペランドは数値の昇格を受けて。に変わるintため、技術的には32ビットを表示する必要があります。

なぜマスクを使用する必要があるの& 0xffですか?

これは、負のバイトを正のバイトとして扱うためです。ints本質的には何toUnsignedIntをしているのでしょうか。負でないバイトに対しては何もしませんが、負のバイトに対しては、次のように言います-1。

1111 1111

int数値の昇格により変換されると、32ビットに符号拡張されます。つまり、符号は負のままになります。基本的に、これは、数値が負の場合は1を埋め、それ以外の場合は0を埋めることを意味します。したがって、次のように-1なります。

1111 1111 1111 1111 1111 1111 1111 1111

これを使用する<< 8と、次のようになります。

1111 1111 1111 1111 1111 1111 0000 0000

これは-256です。さて、& 0xff前にやったらどうなるか見てみましょう<< 8。数値昇格が発生し、以前と同じようにバイトが32バイトに変換されますが、& 0xff最下位8ビットしか取得されません。したがって、intは次のようになります。

0000 0000 0000 0000 0000 0000 1111 1111

これは、0で埋められた元のバイトを取得する方法です。そして<< 8、明らかなことをします:

0000 0000 0000 0000 1111 1111 0000 0000
1 Yunnosch Sep 17 2020 at 18:29

example1に示されているコードは、配列の最初の4つの値を取ります(おそらく、「入力ストリーム」またはその値として説明するものが含まれています)。それらを単一の変数、おそらく十分な幅の(符号なし)整数に配置します。

これは、指定しなかったプロトコルに従って、最初の4つの値のおそらく意味的な意味を取得するために行われます。

では、なぜこれらの演算子を使用して、その「回り道」の方法でそうするのでしょうか。

を使用すると& 0xff、下位8ビットのみが使用されるようになります。
これは冗長です。つまり、バイトからの配列の値に依存できるため、ビット7までの値のみが含まれている場合は不要です。それより高いビット(256、512、...の値)は考慮されません。これは、ストリームから配列への1バイトの取得を信頼しない場合に意味があります。
ただし、Javaでは(haroldがコメントで親切に指摘したように)

& 0xffバイトは符号付き型であるため、Javaでは冗長ではありません。したがって、intに変換すると符号拡張され、符号の余分なコピーを削除する必要があります。バイトが符号なしの場合、このような多くのコードを節約できます。

8の倍数である<< Nを使用すると、N8つの「収集された」ビットが結果値の内側の位置に移動し、結果値に正しい影響を与えます。バイトの1つ(ここでは意図的に「最初」を使用しません)は最も低い値の位置に属し、シフトされず、その値はそのまま使用されます。次に高い値のバイトとして1バイトが必要です。つまり、256(0x100)の倍数を表します。等々。

を使用すると|、正しく配置された部品が組み立てられます。

では、なぜこのような複雑な方法でそれを行うのでしょうか。明らかな代替手段は、ビット7を超えるすべてのビットを強制終了してから、ロットを1つの4バイト整数として読み取ることです。
その理由は、エンディアンに対する疑いです。4バイトを特定の順序でメモリに配置すると、1つの4バイト値として読み取られた場合に、環境でターゲットとする値として解釈されるとは思わないかもしれません。これは、最小アドレスのバイトを最小値を表すバイトと見なすか、最大値を表すバイトと見なすかによって、環境によって意見が異なる可能性があるためです。
示されているコードは、選択されたバイトを強制的に高い値に、1つを低い値に、他のバイトをその間に強制します。

Kayaman Sep 17 2020 at 18:28

値を強制的に8ビットバイトにします。

Javaには符号なし型がないため、のバイト値はJavaの性質0xFFとして解釈さ-1れ、32ビット整数にプロモートされ0xFFFFFFFFます。

ビットマスクは、負の値の余分なビットを破棄して、ORビット演算子を使用するときにビットを上書きしないようにすることを目的としています|。

これは、バイト値が255、として解釈され-1、に昇格された例です。int

  1111 1111 1111 1111 1111 1111 1111 (-1, but was originally an unsigned byte of 255)
& 0000 0000 0000 0000 0000 1111 1111 (0xff)
  ----------------------------------
  0000 0000 0000 0000 0000 1111 1111 (an int with the original value of 255)
Ecto Sep 17 2020 at 18:32

これらは二項演算です。

正確には何が起こりますか?

& 0xFF基本的手段は、あなたが最後のバイトを取ります。

2進数と(&)は、1が同じ位置の両方の数値にある場合にのみ結果の位置が1になることを意味します(それ以外の場合は0)。

別の例があります:

  0000 0001 0000 1100 (268)
& 0000 0000 1111 1111 (0xff)
  -------------------
  0000 0000 0000 1100 (12)

12はどうなりますか?

  0000 0000 0000 1100 (12)
& 0000 0000 1111 1111 (0xff)
  -------------------
  0000 0000 0000 1100 (12)

シフト:

左シフトはビットを左にプッシュするだけです。

  0000 0000 0000 1100 (12)
<< 8
  -------------------
  0000 1100 0000 0000 (3072)

26はどうなりますか?

  0000 0000 0001 1010 (26)
& 0000 0000 1111 1111 (0xff)
  -------------------
  0000 0000 0001 1010 (26)

なぜマスクと0xffを使用する必要があるのですか?

この場合、あなたはしません。ただし、より大きな数(または負の数)で作業した場合は、マスクを使用する必要がある場合があります。また、余分な厄介なビットがないことを確認してください。

それをすべてまとめると、または:

はい、基本的には追加ですが、この場合のみです。実際に起こることは、作成したバイト& 0xFFを並べて番号を作成することです。これが、8の乗算でシフトしている理由です。すべてのバイトにはサイズ8の独自の場所があります。

バイトX、Y、Z、Wがあるとしましょう。次に、次の(X<<24)|(Y<<16)|(Z<<8)|Wように2進数で作成された数値を作成しますXYZW。注意してください、それはこれらの数の合計である必要はありません。