Ein bitweises UND mit Einsen wird das Bitmuster vom anderen Operanden abrufen. Bedeutung, 10101 & 11111 = 10101
. Wenn das Ergebnis dieses bitweisen UND 0 ist, wissen wir, dass der andere Operand 0 ist. Ein Ergebnis von 0, wenn ein einzelnes Byte mit 0xFF
(Einsen) UND-verknüpft wird, wird ein NULL-Byte anzeigen.
Der Code selbst überprüft jedes Byte des Char-Arrays in Vier-Byte-Partitionen. HINWEIS: Dieser Code ist nicht tragbar; Auf einer anderen Maschine oder einem anderen Compiler könnte ein vorzeichenloser Int-Wert mehr als 4 Bytes betragen. Es wäre wahrscheinlich besser, den uint32_t
-Datentyp zu verwenden, um 32-Bit-Ganzzahlen ohne Vorzeichen zu gewährleisten.
Das erste, was zu beachten ist, dass auf einer Little-Endian-Maschine die Bytes, aus denen das Zeichen-Array besteht, in umgekehrter Reihenfolge in einen vorzeichenlosen Datentyp eingelesen werden; Das heißt, wenn die vier Bytes an der aktuellen Adresse das Bitmuster sind, das abcd
entspricht, dann enthält die vorzeichenlose Variable das Bitmuster entsprechend dcba
.
Die zweite besteht darin, dass eine in C konstante hexadezimale Zahl zu einer int-großen Zahl mit den angegebenen Bytes am kleinen Ende des Bitmusters führt. Bedeutung, 0xFF
ist eigentlich 0x000000FF
beim Kompilieren mit 4-Byte-Ints. 0xFF00
ist 0x0000FF00
. Und so weiter.
So sucht das Programm grundsätzlich nach dem NULL-Zeichen in den vier möglichen Positionen. Wenn in der aktuellen Partition kein NULL-Zeichen vorhanden ist, wird mit dem nächsten Vier-Byte-Slot fortgefahren.
Nehmen Sie das Char-Array abcdef
für ein Beispiel. In C haben String-Konstanten immer Null-Terminatoren am Ende, also gibt es ein 0x00
Byte am Ende dieser Zeichenkette.
Es wird funktionieren wie folgt:
Read "ABCD" in unsigned int x:
x: 0x64636261 [ASCII representations for "dcba"]
prüfen jedes Byte für einen Nullabschluss:
0x64636261
& 0x000000FF
0x00000061 != 0,
0x64636261
& 0x0000FF00
0x00006200 != 0,
und überprüfen Sie die anderen zwei Positionen; Es gibt keine Null-Terminatoren in dieser 4-Byte-Partition, also gehe zur nächsten Partition.
Read "ef" in unsigned int x:
x: 0xBF006665 [ASCII representations for "fe"]
Notiere die 0xBF Byte; Das ist nach der Länge der Zeichenfolge, also lesen wir in Müll vom Laufzeit-Stack. Es könnte alles sein. Auf einer Maschine, die keine nicht ausgerichteten Zugriffe zulässt, stürzt sie ab, wenn der Speicher nach der Zeichenfolge nicht 1-Byte-ausgerichtet ist. Wenn nur ein Zeichen in der Zeichenfolge verblieben wäre, würden wir zwei zusätzliche Bytes lesen, so dass die Ausrichtung des Speichers neben dem char-Array 2-Byte-ausgerichtet sein müsste.
prüfen jedes Byte für einen Nullabschluss:
0xBF006665
& 0x000000FF
0x00000065 != 0,
0xBF006665
& 0x0000FF00
0x00006600 != 0,
0xBF006665
& 0x00FF0000
0x00000000 == 0 !!!
So kehren wir len + 2
; len
war 4, da wir es einmal um 4 inkrementiert haben, also geben wir 6 zurück, was tatsächlich die Länge der Zeichenkette ist.
Es handelt undefiniertes Verhalten für eine sehr fragwürdige Beschleunigung (es ist sehr wahrscheinlich noch langsamer). Und ist nicht standardkonform, weil es 'int' anstelle von' size_t' zurückgibt. – Olaf
Ja, verursacht das nicht Probleme, wenn der int-Typ größer als 4 Bytes wird oder wenn die Maschine nicht little-endian ist? –
@MillieSmith: Das ist das geringste Problem, da die meisten 64-Bit-Systeme I32LP64 (POSIX) sind. Problem ist nicht ausgerichteter Zugang, Endianess (wie du gesagt hast). Selbst wenn nicht ausgerichtete Zugriffe auf der Plattform erlaubt sind, können sie viel langsamer sein als ausgerichtete Zugriffe. Nicht zu vergessen die Mehrfachmaske und bedingte Operationen. – Olaf