Im folgenden Code:
short = ((byte2 << 8) | (byte1 & 0xFF))
Was ist der Zweck von &0xFF
? Weil andere manchmal sehe ich es geschrieben als:
short = ((byte2 << 8) | byte1)
Und das scheint auch gut zu funktionieren?
Im folgenden Code:
short = ((byte2 << 8) | (byte1 & 0xFF))
Was ist der Zweck von &0xFF
? Weil andere manchmal sehe ich es geschrieben als:
short = ((byte2 << 8) | byte1)
Und das scheint auch gut zu funktionieren?
wenn byte1
ein 8-Bit-Integer-Typ ist, dann ist es sinnlos – wenn es mehr als 8 Bit sind, erhalten Sie im Wesentlichen die letzten 8 Bit des Werts:
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
& 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
-------------------------------
0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1
John Colanduoni
Anding einer Ganzzahl mit 0xFF
lässt nur das niedrigstwertige Byte übrig. Um beispielsweise das erste Byte in a zu erhalten short s
Du kannst schreiben s & 0xFF
. Dies wird typischerweise als “Maskierung” bezeichnet. Wenn byte1
ist entweder ein Single-Byte-Typ (wie uint8_t
) oder bereits kleiner als 256 ist (und daher bis auf das niedrigstwertige Byte alle Nullen sind), müssen die höherwertigen Bits nicht ausgeblendet werden, da sie bereits Null sind.
Sehen TristopiePatrick Schlüters Antwort unten, wenn Sie möglicherweise mit signierten Typen arbeiten. Bei bitweisen Operationen empfehle ich, nur mit vorzeichenlosen Typen zu arbeiten.
Patrick Schlüter
Die Gefahr des zweiten Ausdrucks kommt, wenn der Typ von byte1
ist char
. In diesem Fall können einige Implementierungen es haben signed char
was bei der Auswertung zu einer Vorzeichenerweiterung führt.
signed char byte1 = 0x80;
signed char byte2 = 0x10;
unsigned short value1 = ((byte2 << 8) | (byte1 & 0xFF));
unsigned short value2 = ((byte2 << 8) | byte1);
printf("value1=%hu %hx\n", value1, value1);
printf("value2=%hu %hx\n", value2, value2);
wird drucken
value1=4224 1080 right
value2=65408 ff80 wrong!!
Ich habe es auf gcc v3.4.6 auf Solaris SPARC 64 Bit versucht und das Ergebnis ist das gleiche mit byte1
und byte2
deklariert als char
.
TL;DR
Die Maskierung dient dazu, eine implizite Zeichenerweiterung zu vermeiden.
BEARBEITEN: Ich habe es überprüft, es ist das gleiche Verhalten in C++.
EDIT2: Wie angeforderte Erklärung der Zeichenerweiterung. Die Vorzeichenerweiterung ist eine Folge davon, wie C Ausdrücke auswertet. Es gibt eine Regel in C, die Promotion-Regel genannt wird. C wandelt implizit alle kleinen Typen in um int
bevor Sie die Auswertung vornehmen. Mal sehen, was mit unserem Ausdruck passiert:
unsigned short value2 = ((byte2 << 8) | byte1);
byte1
ist eine Variable, die das Bitmuster 0xFF enthält. Wenn char
ist unsigned
dieser Wert wird als 255 interpretiert, falls dies der Fall ist signed
es ist -128. Bei der Berechnung erweitert C den Wert auf an int
Größe (im Allgemeinen 16 oder 32 Bit). Das heißt, wenn die Variable ist unsigned
und wir behalten den Wert 255, das Bitmuster dieses Werts bei int
wird 0x000000FF sein. Wenn ja signed
Wir wollen den Wert -128, dessen Bitmuster 0xFFFFFFFF ist. Das Zeichen wurde auf die Größe des für die Berechnung verwendeten Temporärs erweitert. Und somit führt das Oring des Temporärs zu einem falschen Ergebnis.
Bei der x86-Assemblierung erfolgt dies mit der movsx
Anweisung (movzx
für die Nullausdehnung). Andere CPUs hatten dafür andere Anweisungen (6809 hatte SEX
).
+1 für die Warnung, aber ich verstehe nicht warum oder was “Sign Extension” ist, können Sie mit einer einfachen Erklärung bearbeiten?
– doc_id
14. Januar 2021 um 17:08 Uhr
Hier eine kurze Erklärung. Sie sollten den Link nachschlagen, den ich dort gesetzt habe, um mehr über die Beförderungsregeln von C zu erfahren, da es ein sehr wichtiger Punkt ist, dass Leute, sogar erfahrene Programmierer, sich in Bezug auf die Sprache irren.
– Patrick Schlüter
15. Januar 2021 um 14:20 Uhr
sr01853
Angenommen Ihr byte1
ist ein Byte (8 Bits). Wenn Sie ein bitweises UND eines Bytes mit 0xFF ausführen, erhalten Sie dasselbe Byte.
So byte1
ist das gleiche wie byte1 & 0xFF
Sagen byte1
ist 01001101
dann byte1 & 0xFF = 01001101 & 11111111 = 01001101 = byte1
Wenn byte1 von einem anderen Typ ist, sagen wir eine ganze Zahl von 4 Bytes, hinterlässt bitweises AND mit 0xFF das niederwertigste Byte (8 Bits) von Byte1.
Jerry Sarg
Das byte1 & 0xff
sorgt dafür, dass nur die 8 niederwertigsten Bits aus byte1
kann ungleich Null sein.
wenn byte1
ist bereits ein vorzeichenloser Typ, der nur 8 Bit hat (z. B. char
in manchen Fällen bzw unsigned char
in den meisten Fällen) macht es keinen Unterschied/ist völlig unnötig.
Wenn byte1
ist ein Typ, der signiert ist oder mehr als 8 Bit hat (z. B. short
, int
, long
) und eines der Bits außer den 8 niederwertigsten gesetzt ist, dann wird es einen Unterschied geben (dh es werden diese oberen Bits vorher auf Null gesetzt or
ing mit der anderen Variablen, also dieser Operand der or
beeinflusst nur die 8 niederwertigsten Bits des Ergebnisses).
Nein, siehe meine Antwort oben. Wenn die Art von byte1
ist char
oder signed char
es ist absolut notwendig.
– Patrick Schlüter
5. Februar 2013 um 17:54 Uhr
Daumenmücken
es löscht alle Bits, die nicht im ersten Byte sind
Nein, siehe meine Antwort oben. Wenn die Art von byte1
ist char
oder signed char
es ist absolut notwendig.
– Patrick Schlüter
5. Februar 2013 um 17:54 Uhr
Alexej Frunze
& 0xFF
allein sorgt nur dafür, dass Bytes, die länger als 8 Bit sind (vom Sprachstandard erlaubt), den Rest ignorieren.
Und das scheint auch gut zu funktionieren?
Wenn das Ergebnis größer als endet SHRT_MAX
, erhalten Sie undefiniertes Verhalten. Insofern werden beide gleich schlecht funktionieren.
Ist Byte1 vom Typ
uint8_t
?– Shahbaz
5. Februar 2013 um 17:17 Uhr
Dann denke ich, es ist nur “nur um sicher zu gehen”. Wahrscheinlich hat derjenige, der es geschrieben hat, versucht, auf Nummer sicher zu gehen, falls jemand die Art von ändert
byte1
was ziemlich wahrscheinlich scheint, weilbyte2
ist schon nicht 8-bit (sonstbyte2 << 8
ist 0)– Shahbaz
5. Februar 2013 um 17:33 Uhr
Es tut uns leid,
byte2 << 8
funktioniert auch wennbyte2
ist ein 8-Bit-Typ. Standardmäßig funktionieren Ausdrücke immer alsint
. Der Compiler sieht implizit den Ausdruck als((int)byte2) << ((int)8)
– Patrick Schlüter
5. Februar 2013 um 17:40 Uhr
Übrigens,
short
ist ein reserviertes Wort und kann nicht als Variablenname verwendet werden.– Patrick Schlüter
5. Februar 2013 um 17:46 Uhr