Tutorials - Bitweise Operatoren und Bit Manipulations in C und C
Von Alex Allain
Im Allgemeinen als Programmierer müssen Sie nicht selbst über Operationen auf Bit-Ebene befassen. Sie sind frei in Bytes zu denken, oder ints und verdoppelt oder noch höhere Datentypen von einer Kombination aus diesen bestehen. Aber es gibt Zeiten, wenn Sie möchten in der Lage sein, auf das Niveau eines einzelnen Bits zu gehen. Exklusiv-oder-Verschlüsselung ist ein Beispiel, wenn Sie bitweise Operationen benötigen.
Schließlich können Sie Bit-Operationen verwenden Ihr Programm zu beschleunigen oder nette Tricks auszuführen. (Dies ist nicht immer das Beste, was zu tun ist.)
Das Nachdenken über Bits
Der Betreiber ist Leftshift das Äquivalent alle Bits einer Zahl, die eine bestimmte Anzahl von Stellen nach links zu bewegen: Betrachten wir zum Beispiel die Zahl 8 in binärer 00001000. geschrieben Wenn wir es auf die linke Seite an 2 Stellen verschieben wollten, würden wir am Ende mit 00100000; alles ist mit den linken zwei Stellen bewegt, und Nullen werden als Polsterung hinzugefügt. Dies ist die Nummer 32 - in der Tat, nach links Verschiebung ist das Äquivalent von einer Potenz von zwei zu multiplizieren. Man beachte, dass in diesem Beispiel verwenden wir ganze Zahlen, die entweder 2 oder 4 Bytes, und dass die Operation auf die gesamte Sequenz von 16 oder 32 Bits angewandt wird.
Aber was passiert, wenn wir eine Zahl wie 128 verschieben und wir es nur in einem einzigen Byte zu speichern: 10000000? Nun, 128 * 2 = 256, und wir können nicht einmal speichern Sie eine Nummer, die groß in einem Byte, also ist es nicht überraschend sein, dass das Ergebnis 00000000 ist.
Es sollte nicht überraschen, dass es ein entsprechender rechten Shift-Operator: >> (besonders wenn man bedenkt, dass ich es früher erwähnt). Beachten Sie, dass eine bitweise Verschiebung nach rechts um 2 entspricht ganzzahlige Division ist.
Warum ist es Integer-Division? Betrachten Sie die Nummer 5, in Binär-, 00000101. 5/2 beträgt 2,5, aber wenn man ganzzahlige Division durchführen, 5/2 beträgt 2. Wenn Sie eine Verschiebung nach rechts durch eine durchführen: (unsigned int) 5 >> 1, Sie beenden mit bis 00000010, da das am weitesten rechts liegenden 1 wird das Ende verschoben off; dies ist die Darstellung der Zahl 2. Beachten Sie, dass dies gilt nur gilt für ganze Zahlen ohne Vorzeichen; andernfalls sind garantiert wir nicht, dass die Füllbits alle 0s sein.
Im Allgemeinen wird zur Folge haben, die linke und rechte Shift-Operatoren in deutlich schnelleren Code als zu berechnen und dann durch eine Potenz von zwei multipliziert wird. Die Shift-Operatoren werden auch nützlich sein, später, wenn wir, wie sehen einzelne Bits zu manipulieren.
Vorerst wollen wir uns einige der anderen Binäroperatoren schauen, um zu sehen, was sie für uns tun können.
Logisches UND
Die bitweise AND-Operator ist ein einzelne Und-Zeichen: -. Ein handliches mnemonic ist, dass die kleine Version des boolean AND, -, Arbeiten auf kleinere Stücke (Bits anstelle von Bytes, Zeichen, Zahlen, usw.). Im Wesentlichen nimmt eine binäre UND einfach die logische UND-Verknüpfung der Bits in jeder Position einer Zahl in binärer Form.
Zum Beispiel arbeitet mit einem Byte (der Typ char): Die höchstwertigen Bits der ersten Zahl ist 0, so dass wir das signifikanteste Bit des Ergebnisses wissen 0 sein muss; in dem zweiten höchstwertigen Bit ist das Bit der zweiten Zahl Null, so haben wir das gleiche Ergebnis. Das einzige Mal, wo beide Bits 1 sind, die die einzige Zeit ist das Ergebnis 1 sein wird, ist das fünfte Bit von links. Folglich,
bitweise OR
Bitweise OR arbeitet fast genau die gleiche Art und Weise wie bitweise AND. Der einzige Unterschied besteht darin, dass nur eine der beiden Bits a 1 für diese Position des Bit im Ergebnis sein muss 1 sein (wenn beide Bits eine 1 sind, wird das Ergebnis ebenfalls eine 1 in dieser Position haben.) Das Symbol ist ein Rohr: |. Auch dies ist ähnlich logischen Operator boolean, die || ist. und folglich nehmen wir einen Blick auf ein Beispiel, wenn Sie nur diese vier Operatoren verwenden könnte etwas potenziell nützlich zu machen. Sagen wir, dass Sie den Überblick über bestimmte boolean Attribute über etwas halten wollte - zum Beispiel, könnte man acht Autos haben und wollen, um zu verfolgen, die in Gebrauch sind (!). Lassen Sie sich jedes der Autos eine Zahl von 0 bis 7 zugewiesen werden.
Dieses Verfahren funktioniert für das Bit in der n-ten Position zu finden. Das einzige, was noch zu tun ist, um eine Zahl zu schaffen, mit nur ein Bit in der richtigen Position eingeschaltet. Dies sind nur Zweierpotenzen, so ein Ansatz könnte sein, etwas zu tun: Während diese Funktion funktioniert, kann es verwirrend sein. Es verschleiert die Tatsache, dass wir wollen, was zu tun ist, etwas über eine bestimmte Anzahl von Orten zu verschieben, so dass wir eine Zahl wie 00100000 haben - ein paar Nullen, eine ein, und ein paar mehr Nullen. (Das könnte man auch erste oder letzte sein - 10000000 oder 00000001)
Wir können eine bitweise Leftshift verwenden, um dies zu erreichen, und es wird viel schneller zu booten. Wenn wir mit der Nummer 1 beginnen, sind wir nur ein einziges Bit haben garantiert, und wir wissen, dass es auf die weit rechts. Wir werden nicht vergessen, dass Auto 0 seine Daten in der rechten Bit gespeichert hat, und Auto 7 wird die äußerste linke sein. Beachten Sie, dass durch Nullstellen Verschiebung ein rechtlicher Betrieb ist - wir werden nur die gleiche Anzahl wieder begannen wir mit.
jetzt tun können, alles, was wir überprüfen, ob ein Auto in Gebrauch ist; wir können nicht wirklich festgelegt, die in-Use-Bit für sie. Es gibt zwei Fälle zu betrachten: angibt, ein Auto in Gebrauch ist, und ein Auto aus der Benutzung entfernt wird. In einem Fall müssen wir ein wenig auf, und in der anderen drehen, drehen ein wenig ab.
Lassen Sie uns auf das Problem des Drehens des Bit angehen. Was sagt das wir tun sollten? Wenn wir ein bisschen auf Null gesetzt haben, ist die einzige Art, wie wir jetzt wissen, dass es auf 1 gesetzt ist, eine bitweise zu tun OR. Günstig, wenn wir eine bitweise OR mit nur einem einzigen Bit auf 1 gesetzt (der Rest sind 0) durchführen, dann werden wir nicht den Rest der Zahl beeinflussen, weil alles verodert mit Null gleich bleibt (1 oder 0 1 ist, und 0 oder 0: 0).
Auch hier brauchen wir ein einzelnes Bit in die richtige Position zu bewegen: Was macht das? Nehmen wir den Fall der Einstellung des Bit ganz rechts zum 1: wir eine bestimmte Anzahl haben 0XXXXXXX | 10000000; das Ergebnis, 1XXXXXXX. Die Verschiebung ist das gleiche wie zuvor; der einzige Unterschied ist der Betreiber und dass wir speichern das Ergebnis.
ein Auto Einstellung nicht mehr in Gebrauch zu sein, ist etwas komplizierter. Dafür werden wir einen anderen Betreiber benötigen.
Das bitweise Komplement
Der bitweise Komplement-Operator, die Tilde,
jedes Bit Flips. Ein nützlicher Weg, dies zu erinnern ist, dass die Tilde manchmal ein twiddle genannt wird, und das bitweise Komplement Rotationsdaten jedes Bit: Wenn Sie ein 1 haben, ist es ein 0, und wenn Sie ein 0 haben, ist es ein 1.
Dies erweist sich als ein guter Weg zu sein, den größtmöglichen Wert für eine Zahl ohne Vorzeichen zu finden: 0, ist natürlich alle 0s: 00000000 00000000 Sobald wir 0 twiddle, erhalten wir alle 1s: 11111111 11111111 Da max ein unsigned int wir müssen nicht über Vorzeichenbits oder Zweier-Komplement kümmern. Wir wissen, dass alle 1s die größtmögliche Zahl ist.
und. können nicht untereinander ausgetauscht werden. Wenn Sie die logische nehmen nicht von einer Nicht-Null-Nummer, erhalten Sie 0 (FALSCH). Wenn Sie jedoch eine von Null verschiedene Zahl twiddle, die einzige Zeit, die Sie bekommen 0 ist, wenn jedes Bit eingeschaltet wird. (Diese nicht-Äquivalenzprinzip für bitweise gilt und auch, es sei denn, Sie wissen, dass Sie genau die Zahlen 1 und 0. Für bitweise verwenden OR, um sicher zu sein, dass es gleichbedeutend wäre, dann würden Sie müssen sicherstellen, dass die zugrunde liegenden Darstellung von 0 nur Nullen es austauschbar zu verwenden. Aber tun sie das nicht! es wird Ihr Code schwerer verständlich machen.)
Nun, da wir einen Weg von Spiegeln Bits haben, können wir anfangen, darüber nachzudenken, wie ein einzelnes Bit auszuschalten. Wir wissen, dass wir nicht betroffen anderen Bits verlassen wollen, aber dass, wenn wir eine 1 in der gegebenen Position haben, wollen wir es eine 0 Nehmen Sie sich etwas Zeit, um darüber nachzudenken, wie diese weiter vor dem Lesen zu tun.
Wir müssen mit einer Folge von Operationen zu entwickeln, die nicht betroffenen 1en und 0en in der Nicht-Zielposition verlassen; vor, verwendeten wir eine bitweise OR, aber wir können auch eine bitweise AND. 1 und 1 1 und 0 und 1 0 ist, jetzt ein bisschen auszuschalten, wir müssen nur mit zur 0 AND: 1 und 0 sind 0. Wenn wir also das Auto 2 nicht mehr in Gebrauch, um anzuzeigen, wollen wollen wir die bitweise AND von XXXXX1XX mit 11111011 nehmen.
Wie können wir diese Nummer? Dies ist, wo die Fähigkeit, das Komplement einer Zahl zu nehmen ist praktisch: Wir wissen bereits, wie ein einzelnes Bit einzuschalten. Wenn wir auf ein Bit drehen und das Komplement der Zahl nehmen, erhalten wir jedes Bit auf, außer dass Bit: Nun, da wir diese haben, können wir nur das bitweise nehmen und werden diese mit dem aktuellen Feld von Autos, und das nur wenig wir ‚ll Änderung ist die eine der car_num wir interessiert sind. man könnte sich denken, aber dies ist eine Art klobig. Wir müssen wirklich wissen, ob ein Auto in Betrieb ist oder nicht (wenn das Bit ein- oder ausgeschaltet ist), bevor wir wissen können, welche nennen funktionieren. Dies ist zwar nicht unbedingt eine schlechte Sache ist, bedeutet es, dass wir ein wenig darüber wissen müssen, was los ist. Es ist ein einfacher Weg, aber zuerst müssen wir den letzten Bit-Operator: Exklusiv-Oder.
Bitweise Exklusiv-Oder (XOR)
Es gibt keinen Booleschen Operator Pendant zum bitweise Exklusiv-Oder, aber es gibt eine einfache Erklärung. Die Exklusiv-ODER-Operation dauert zwei Eingänge und gibt eine 1, wenn entweder der eine oder der andere der Eingänge eine 1 ist, aber nicht, wenn beide sind. Das heißt, wenn beide Eingänge 1 oder beide Eingänge 0 sind, wird 0 zurückgegeben bitweise exklusive oder mit dem Betreiber eines caret, ^, führt die Exklusiv-ODER-Operation für jedes Paar von Bits. Exklusiv-Oder wird allgemein XOR abgekürzt.
Zum Beispiel, wenn Sie zwei Zahlen binär dargestellt als 10101010 und 01110010 dann die bitweise XOR-Ergebnisse in 11011000. nehmen Es ist einfacher, dies zu sehen, ob die Bits korrekt ausgerichtet sind: Sie können auf folgende Weise von XOR denken: Sie haben einige Bit, entweder 1 oder 0, dass wir A. nennen wollen wenn Sie eine XOR 0 nehmen, dann erhalten Sie immer einen zurück: wenn A 1 ist, erhalten Sie 1, und wenn A 0 ist, erhalten Sie 0. Anderer Hand, wenn Sie eine XOR-1 nehmen Sie Flip A. Wenn A 0 ist, erhalten Sie 1; wenn A 1 ist, erhalten Sie 0.
So können Sie sich denken, der XOR-Operation als eine Art selektive twiddle: Wenn Sie XOR auf zwei Zahlen gelten, von denen alle 1s, Sie das Äquivalent eines twiddle bekommen.
Wenn Sie darüber hinaus die XOR-Operation anwenden zweimal - sagen Sie etwas haben, A und ein anderes Bit B, und Sie setzen C gleich A XOR B, und dann nehmen C XOR B: Sie A XOR B XOR B erhalten, die im wesentlichen dreht entweder jedes Bit der A zweimal, oder kippt nie das Bit, so dass Sie nur A. als Übung (Sie können auch als Auslöschung. denken Sie an B XOR B) zurück, können Sie denken Sie an einen Weg, dies zu nutzen, um Austausch zwei integer-Variablen, ohne eine temporäre Variable? (Wenn Sie es herausgefunden haben, überprüfen Sie die Lösung.)
Wie kommt uns dabei helfen? Nun, erinnere mich an die erste Prinzip: ein wenig mit 0 Ergebnisse in der gleichen Bit-XOR-Verknüpfung. Also, was würden wir wirklich in der Lage sein mag nur eine Funktion zu tun ist, aufrufen, die die Bit des Auto kippt uns interessiert - es spielt keine Rolle, ob es ein- oder ausgeschaltet eingeschaltet ist wird - und überlässt den Rest der Bits unverändert.
Das klingt sehr viel wie das, was wir in der Vergangenheit getan haben; in der Tat, wir brauchen nur eine Änderung unserer Funktion, um ein wenig einzuschalten. Statt eine bitweise zu verwenden oder verwenden wir eine bitweise XOR. Dies läßt alles unverändert, aber kippt das Bit, anstatt es immer einschalten zu müssen:
Wann sollten Sie bitweise Operatoren verwenden?
0 die größtmögliche ganze Zahl zu finden. Und Bit mit zwei multiplizieren Verschiebung ist eine ziemlich häufige Operation, so dass es nicht die Lesbarkeit in der Art und Weise wirkt sich die Verwendung von Bit-Manipulations Advanced kann in einigen Fällen (zum Beispiel XOR mit den Werten in zwei Variablen gespeichert wechseln).
Es gibt auch Zeiten, in denen Sie bitweise Operatoren verwenden müssen: Wenn Sie mit Kompression oder einigen Formen der Verschlüsselung arbeiten, oder wenn Sie auf einem System arbeiten, die Bit-Felder verwendet werden erwartet boolean Attribute zu speichern.
Sie sollten nun mit sechs Bit-Operatoren vertraut sein:
Arbeitet auf Bits für linkes Argument nimmt eine ganze Zahl als zweites Argument Verschiebt Bits von bit_arg shift_arg Stellen nach links - äquivalent zu einer Multiplikation mit 2 ^ shift_arg Bits verschiebt mich zu den bit_arg shift_arg Stellen nach rechts - äquivalenter Teilung auf ganzzahlige durch 2 ^ shift_arg
Arbeiten auf den Bits beider Argumente sind die bitweise AND von left_arg und right_arg sind die bitweise XOR von left_arg und right_arg Arbeiten auf den Bits nur Argument Kehren die Bits von arg
Fähigkeiten und Kenntnisse Sie kennen auch ein paar nette Tricks, die Sie verwenden können, wenn die Leistung entscheidend ist, oder Raum ist langsam, oder Sie nur einzelne Bits einer Zahl isolieren müssen und manipulieren.
Und Sie sollten jetzt ein besseres Gefühl für das, was auf der niedrigsten Ebene des Computers geht weiter.
A Parting Puzzle
Ein letzter netter Trick von Bitoperatoren ist, dass man sich in Verbindung mit einem wenig Mathematik verwenden, um herauszufinden, ob eine ganzen Zahl eine Potenz von zwei ist. Nehmen Sie sich etwas Zeit, um darüber nachzudenken, dann die Lösung überprüfen. In Verbindung stehende Artikel
Ein wenig Hintergrund in Bits und ein paar anderen Tricks