Was macht 0xff << n in Java?

Sep 17 2020

Von einem Inputstream habe ich die ersten 4 Bytes gelesen und diese gepackt, um in diesem Fall einige Informationen über die Größe / Länge des Streams zu erhalten.

Dafür verwende ich den folgenden Code (Beispiel 1), den ich aus einem anderen Projekt kopiere

Beispiel 1: Verwendet ein Byte-Array, bei dem die Werte aus InputStream in das Array mit dem Namen in_buf [] mit Länge 4 eingelesen werden und dessen Werte {0,0,12,26} sind.

Beispiel 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

und als Ergebnis werde ich der Wert der Größe, schön aber ..

Ich muss erklären, was hier passiert, und ich versuche, alle Funktionen aufzuteilen, um besser zu sehen, was passiert, und zu debuggen, und ich werde zu folgenden Ergebnissen

    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

dann schließe ich aus Beispiel 1, dass das Ergebnis der Größe die Summe von 0 + 0 + 3072 + 26 ist, aber was genau passiert hier (nur mit den Werten 12 und 26)? oder welche Operation wird durchgeführt?

Etwas wie das ?

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

Und warum brauchen wir die Maske & 0xff ?

Denn wenn Sie int byte3a = (in_buf [3] & 0xff) debuggen, ist das Ergebnis dasselbe wie int byte3b = in_buf [3]; also 12 , * wobei der Wert von in_buf [3] = 12 ist; Ich füge ein Bild aus meinen Debug-Ergebnissen hinzu.

Was passiert oder macht das in_buf [3] & 0xff so etwas?

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

Screenshot von Eclipse

Antworten

4 Sweeper Sep 17 2020 at 18:27

so etwas?

Ja, außer dass die Operanden einer numerischen Heraufstufung unterzogen werden und sich in eine verwandeln. intDaher sollten Sie technisch 32 Bit anzeigen.

und warum brauchen wir die Maske & 0xff?

Dies ist so, dass wir negative Bytes als positiv behandeln ints, im Wesentlichen was toUnsignedIntgetan wird. Es tut nichts für nicht negative Bytes, aber für ein negatives Byte, sagen wir -1:

1111 1111

Wenn das konvertiert wird intaufgrund numerischer Förderung, wird es ein Vorzeichen erweiterten 32-Bits. Das heißt, das Vorzeichen bleibt negativ. Grundsätzlich bedeutet dies, dass wir, wenn die Zahl negativ ist, 1s auffüllen, andernfalls 0s auffüllen. So -1wird:

1111 1111 1111 1111 1111 1111 1111 1111

Wenn Sie nun das verwenden << 8, wird es sein:

1111 1111 1111 1111 1111 1111 0000 0000

das ist -256. Nun wollen wir sehen, was passiert, wenn Sie es & 0xffvorher tun << 8. Die numerische Heraufstufung erfolgt und konvertiert Ihr Byte wie zuvor in 32, & 0xfferhält jedoch nur die 8 niedrigstwertigen Bits! So wird das int jetzt:

0000 0000 0000 0000 0000 0000 1111 1111

Auf diese Weise erhalten Sie Ihr Originalbyte, das mit Nullen aufgefüllt wird. Und dann << 8macht das Offensichtliche:

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

Der in Beispiel 1 gezeigte Code verwendet die ersten vier Werte des Arrays (das vermutlich das enthält, was Sie als "Eingabestream" oder dessen Werte bezeichnen). Es ordnet sie in einer einzigen Variablen an, vermutlich einer (vorzeichenlosen) Ganzzahl mit ausreichender Breite.

Dies geschieht, um die vermutlich semantische Bedeutung der ersten vier Werte gemäß einem von Ihnen nicht angegebenen Protokoll zu erhalten.

Warum also auf diese Art und Weise mit diesen Operatoren?

Die Verwendung von & 0xffstellt sicher, dass nur die unteren 8 Bit verwendet werden.
Dies ist redundant, dh nicht erforderlich, wenn Sie sich darauf verlassen können, dass die Werte im Array aus Bytes stammen und daher nur Werte bis zu Bit 7 enthalten. Ohne höhere Bits (Wert 256, 512, ...) werden diese berücksichtigt. Dies ist sinnvoll, wenn Sie dem Abrufen einzelner Bytes aus dem Stream in das Array nicht vertrauen.
Allerdings in Java (wie Harold freundlicherweise in einem Kommentar hervorhob)

& 0xffist in Java nicht redundant, da Byte ein vorzeichenbehafteter Typ ist und daher bei der Konvertierung in int vorzeichenerweitert wird und diese zusätzlichen Kopien des Vorzeichens entfernt werden müssen. Wenn das Byte nicht signiert wäre, würde so viel Code gespeichert.

Die Verwendung von << N, mit Nwobei ein Vielfaches von 8, bewegt sich die acht „geerntet“ Bits in die Position innerhalb der Ergebniswert, in dem sie die richtige Einfluss auf das Ergebnis Wert haben. Eines der Bytes (ich verwende hier absichtlich nicht "first") gehört in die Position mit dem niedrigsten Wert, es wird nicht verschoben, sein Wert wird unverändert verwendet. Ein Byte wird als das nächsthöhere Byte benötigt, dh es repräsentiert ein Vielfaches von 256 (0x100). Und so weiter.

Die Verwendung von |montiert die korrekt platzierten Teile.

Warum nun so kompliziert? Die naheliegende Alternative besteht darin, einfach alle Bits nach Bit 7 zu töten und dann das Los als eine 4-Byte-Ganzzahl zu lesen.
Der Grund ist der Zweifel an der Endianess. Sie können möglicherweise nicht darauf vertrauen, dass das Anordnen von vier Bytes in einer bestimmten Reihenfolge im Speicher, wenn es als ein 4-Byte-Wert gelesen wird, als der Wert interpretiert wird, auf den Sie in Ihrer Umgebung abzielen. Dies liegt daran, dass unterschiedliche Umgebungen unterschiedliche Meinungen vertreten können, ob das Byte an der niedrigsten Adresse als dasjenige betrachtet werden soll, das die niedrigsten oder die höchsten Werte darstellt.
Der angezeigte Code zwingt ein ausgewähltes Byte auf die hohen Werte, eines auf die niedrigen Werte und die anderen dazwischen.

Kayaman Sep 17 2020 at 18:28

Der Wert wird in ein 8-Bit-Byte gezwungen.

Da Java keine vorzeichenlosen Typen hat, wird ein Bytewert von 0xFFals interpretiert -1und aufgrund der Natur von Java zu einem 32-Bit-Int heraufgestuft, d 0xFFFFFFFF. H.

Die Bitmaske soll diese zusätzlichen Bits für negative Werte verwerfen, damit sie die Bits bei Verwendung des bitweisen Operators OR nicht überschreiben |.

Hier ist ein Beispiel mit dem Byte-Wert 255, obwohl er als interpretiert -1und zu heraufgestuft wirdint

  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

Dies sind binäre Operationen.

Was genau passiert?

Das & 0xFFbedeutet im Grunde, dass Sie das letzte Byte nehmen.

Binär und (&) bedeutet, dass die Ergebnisposition nur dann 1 ist, wenn sich 1 in beiden Zahlen an derselben Position befindet (andernfalls 0).

Es gibt noch ein anderes Beispiel:

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

Was passiert mit 12?

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

Verschiebung:

Linksverschiebung schiebt nur die Bits nach links.

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

Was passiert mit 26?

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

Warum brauchen wir die Maske & 0xff?

In diesem Fall nicht. Wenn Sie jedoch mit größeren Zahlen (oder negativen Zahlen) gearbeitet haben, muss möglicherweise die Maske verwendet werden. Außerdem stellen Sie sicher, dass es keine zusätzlichen unordentlichen Teile gibt.

Alles zusammen mit oder:

Ja, es ist im Grunde eine Ergänzung, aber nur in diesem Fall. Was tatsächlich passiert, ist, dass Sie die von Ihnen erstellten Bytes & 0xFFnebeneinander stellen, um eine Zahl zu erstellen. Aus diesem Grund verschieben Sie um ein Vielfaches von 8 - jedes Byte hat eine eigene Stelle der Größe 8.

Angenommen, Sie haben Bytes X, Y, Z, W. Dann (X<<24)|(Y<<16)|(Z<<8)|Wwird eine binäre Zahl wie folgt erstellt : XYZW. Achtung, es muss nicht die Summe dieser Zahlen sein.