Wie kann man ein Bit setzen, löschen und umschalten?
Antworten
Zu viele Anzeigen?Einstellung eines Bits
Verwenden Sie den bitweisen OR-Operator ( |
), um ein Bit zu setzen.
number |= 1UL << n;
Damit wird die n
ein bisschen number
. n
sollte Null sein, wenn Sie die 1
Bit und so weiter bis zu n-1
wenn Sie die Option n
Das Stück.
Utilice 1ULL
wenn number
ist breiter als unsigned long
Förderung von 1UL << n
erfolgt erst nach der Auswertung der 1UL << n
wo es ein undefiniertes Verhalten ist, sich um mehr als die Breite einer long
. Das Gleiche gilt für alle anderen Beispiele.
Ein wenig aufräumen
Verwenden Sie den bitweisen AND-Operator ( &
), um ein wenig zu löschen.
number &= ~(1UL << n);
Dadurch wird die n
ein bisschen number
. Sie müssen die Bitfolge mit dem bitweisen NOT-Operator invertieren ( ~
), dann UND.
Ein bisschen hin und her schalten
Der XOR-Operator ( ^
) kann verwendet werden, um ein Bit umzuschalten.
number ^= 1UL << n;
Das schaltet die n
ein bisschen number
.
Ein bisschen nachsehen
Sie haben zwar nicht danach gefragt, aber ich kann es trotzdem hinzufügen.
Um ein Bit zu prüfen, verschiebt man die Zahl n nach rechts und setzt sie dann bitweise UND:
bit = (number >> n) & 1U;
Dadurch wird der Wert der n
ein bisschen number
in die Variable bit
.
Ändern der n th Bit zu x
Einstellung der n
Bit entweder auf 1
ou 0
kann bei einer 2er-Komplement-C++-Implementierung wie folgt erreicht werden:
number ^= (-x ^ number) & (1UL << n);
Bit n
wird gesetzt, wenn x
es 1
und gelöscht, wenn x
es 0
. Wenn x
einen anderen Wert hat, erhält man Müll. x = !!x
wird boolesch auf 0 oder 1 gesetzt.
Um dies unabhängig vom Verhalten bei der Negation des 2er-Komplements zu machen (wobei -1
alle Bits gesetzt hat, anders als bei einer 1er-Komplement- oder Vorzeichen/Magnitude-C++-Implementierung), verwenden Sie die Negation ohne Vorzeichen.
number ^= (-(unsigned long)x ^ number) & (1UL << n);
o
unsigned long newbit = !!x; // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);
Es ist im Allgemeinen eine gute Idee, vorzeichenlose Typen für portable Bitmanipulation zu verwenden.
o
number = (number & ~(1UL << n)) | (x << n);
(number & ~(1UL << n))
wird die n
th Bit und (x << n)
setzt die n
th Bit zu x
.
Es ist auch generell eine gute Idee, Code nicht zu kopieren/einzufügen, und so verwenden viele Leute Präprozessormakros (wie die Antwort des Community-Wikis weiter unten ) oder eine Art von Verkapselung.
Verwendung der Standard-C++-Bibliothek: std::bitset<N>
.
Oder die Boost Version: boost::dynamic_bitset
.
Es ist nicht nötig, selbst zu rollen:
#include <bitset>
#include <iostream>
int main()
{
std::bitset<5> x;
x[1] = 1;
x[2] = 0;
// Note x[0-4] valid
std::cout << x << std::endl;
}
[Alpha:] > ./a.out
00010
Die Boost-Version erlaubt ein Bitset in Laufzeitgröße im Vergleich zu einer Standardbibliothek Bitset in Kompilierzeitgröße.
Die andere Möglichkeit ist die Verwendung von Bitfeldern:
struct bits {
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
};
struct bits mybits;
definiert ein 3-Bit-Feld (eigentlich sind es drei 1-Bit-Felder). Bit-Operationen werden nun etwas (haha) einfacher:
Zum Setzen oder Löschen eines Bits:
mybits.b = 1;
mybits.c = 0;
Um ein bisschen zu schalten:
mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1; /* all work */
Ich prüfe ein wenig:
if (mybits.c) //if mybits.c is non zero the next line below will execute
Dies funktioniert nur bei Bitfeldern mit fester Größe. Andernfalls müssen Sie auf die in früheren Beiträgen beschriebenen Techniken zur Bitverschiebung zurückgreifen.
Ich verwende Makros, die in einer Header-Datei definiert sind, um die Bits zu setzen und zu löschen:
/* a=target variable, b=bit number to act upon 0-n */
#define BIT_SET(a,b) ((a) |= (1ULL<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1ULL<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1ULL<<(b)))
#define BIT_CHECK(a,b) (!!((a) & (1ULL<<(b)))) // '!!' to make sure this returns 0 or 1
#define BITMASK_SET(x, mask) ((x) |= (mask))
#define BITMASK_CLEAR(x, mask) ((x) &= (~(mask)))
#define BITMASK_FLIP(x, mask) ((x) ^= (mask))
#define BITMASK_CHECK_ALL(x, mask) (!(~(x) & (mask)))
#define BITMASK_CHECK_ANY(x, mask) ((x) & (mask))
Manchmal lohnt es sich, einen enum
a 名前 die Bits:
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
Verwenden Sie dann die Namen später. D.h. schreiben
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
zum Einstellen, Löschen und Prüfen. Auf diese Weise verbergen Sie die magischen Zahlen vor dem Rest Ihres Codes.
Abgesehen davon unterstütze ich Die Lösung von Paige Ruten .
- See previous answers
- Weitere Antworten anzeigen
90 Stimmen
Lesen Sie dies: graphics.stanford.edu/~seander/bithacks.html und, wenn du das gemeistert hast, lies das hier: realtimecollisiondetection.net/blog/?p=78
22 Stimmen
Das könnte Sie auch interessieren Der Gebissverdreher , Bit Twiddling Hacks und Die Aggregat-Magie-Algorithmen .
0 Stimmen
Das wirft die Frage auf, was die kanonische Frage für mehrere Bits ist.
2 Stimmen
Verwandt: Was sind bitweise Verschiebungsoperatoren (Bit-Shift) und wie funktionieren sie?
2 Stimmen
Einige Kandidaten: Ersetzen von Bits in einem Bitfeld ohne Auswirkungen auf andere Bits mit C (2011), und Wie kann man in C nur bestimmte Bits eines Bytes setzen, ohne den Rest zu beeinflussen? (2010)