Beim Einfügen einer Ganzzahl mit 0xFF
bleibt nur das niedrigstwertige Byte übrig. Um beispielsweise das erste Byte in einem short s
zu erhalten, können Sie s & 0xFF
schreiben. Dies wird typischerweise als „Maskierung“ bezeichnet. Wenn byte1
entweder ein einzelner Bytetyp ist (wie uint8_t
) oder bereits kleiner als 256 ist (und infolgedessen alle Nullen mit Ausnahme des niedrigstwertigen Bytes sind), müssen die höheren Bits nicht maskiert werden, da sie bereits Null sind.
Siehe die Antwort von tristopiaPatrick Schlüter unten, wenn Sie möglicherweise mit signierten Typen arbeiten. Bei bitweisen Operationen empfehle ich, nur mit vorzeichenlosen Typen zu arbeiten.
Wenn byte1
ein 8-Bit-Integer-Typ ist, dann ist es sinnlos – wenn es mehr als 8 Bit ist, wird es Ihnen im Wesentlichen die letzten 8 Bits des Wertes geben:
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
Die Gefahr des zweiten Ausdrucks besteht, wenn der Typ von byte1
char
ist. In diesem Fall können einige Implementierungen es signed char
haben, 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 gedruckt
value1=4224 1080 rightvalue2=65408 ff80 wrong!!
Ich habe es auf gcc v3.4 versucht.6 auf Solaris SPARC 64 Bit und das Ergebnis ist das gleiche mit byte1
und byte2
als char
deklariert.
TL; DR
Die Maskierung besteht darin, eine implizite Vorzeichenerweiterung zu vermeiden.
BEARBEITEN: Ich habe überprüft, es ist das gleiche Verhalten in C ++.
EDIT2: Wie gewünscht Erklärung der Zeichenerweiterung.Die Vorzeichenerweiterung ist eine Folge der Art und Weise, wie C Ausdrücke auswertet. In C gibt es eine Regel namens Promotionsregel. C konvertiert implizit alle kleinen Typen in int
, bevor die Auswertung durchgeführt wird. 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
unsigned
ist, wird dieser Wert als 255 interpretiert, wenn er signed
ist, ist er -128. Bei der Berechnung erweitert C den Wert auf eine Größe int
(im Allgemeinen 16 oder 32 Bit). Dies bedeutet, dass, wenn die Variable unsigned
ist und wir den Wert 255 behalten, das Bitmuster dieses Wertes als int
0x000000FF ist. Wenn es signed
ist, wollen wir den Wert -128, dessen Bitmuster 0xFFFFFFFF ist. Das Zeichen wurde auf die Größe der zur Berechnung verwendeten Zeit erweitert.Und so wird das temporäre Oring das falsche Ergebnis liefern.
Bei der x86-Assembly erfolgt dies mit der Anweisung movsx
(movzx
für die Nullerweiterung). Andere CPUs hatten andere Anweisungen dafür (6809 hatte SEX
).