Wie kann man ein Bit setzen, löschen und umschalten?
Antworten
Zu viele Anzeigen?Wie kann man ein einzelnes Bit setzen, löschen und umschalten?
Um eine häufige Kodierungsfalle beim Versuch, die Maske zu bilden, zu umgehen:
1
ist nicht immer breit genug
Welche Probleme treten auf, wenn number
ist ein breiterer Typ als 1
?
x
kann zu groß für die Verschiebung sein 1 << x
was zu undefiniertes Verhalten (UB). Auch wenn x
ist nicht allzu groß, ~
möglicherweise nicht genügend höchstwertige Bits umkehren.
// assume 32 bit int/unsigned
unsigned long long number = foo();
unsigned x = 40;
number |= (1 << x); // UB
number ^= (1 << x); // UB
number &= ~(1 << x); // UB
x = 10;
number &= ~(1 << x); // Wrong mask, not wide enough
Um sicherzustellen, dass 1 breit genug ist:
Code könnte verwenden 1ull
oder pedantisch (uintmax_t)1
und lassen Sie den Compiler optimieren.
number |= (1ull << x);
number |= ((uintmax_t)1 << x);
Oder die Besetzung - was zu Problemen bei der Kodierung/Überprüfung/Wartung führt, damit die Besetzung korrekt und auf dem neuesten Stand ist.
number |= (type_of_number)1 << x;
Oder fördern Sie sanft die 1
durch Erzwingen einer mathematischen Operation, die mindestens so breit ist wie der Typ der number
.
number |= (number*0 + 1) << x;
Wie bei den meisten Bitmanipulationen arbeiten Sie am besten mit ohne Vorzeichen Typen und nicht unterzeichnet Die
Hier sind einige Makros, die ich verwende:
SET_FLAG(Status, Flag) ((Status) |= (Flag))
CLEAR_FLAG(Status, Flag) ((Status) &= ~(Flag))
INVALID_FLAGS(ulFlags, ulAllowed) ((ulFlags) & ~(ulAllowed))
TEST_FLAGS(t,ulMask, ulBit) (((t)&(ulMask)) == (ulBit))
IS_FLAG_SET(t,ulMask) TEST_FLAGS(t,ulMask,ulMask)
IS_FLAG_CLEAR(t,ulMask) TEST_FLAGS(t,ulMask,0)
Eine schablonenhafte Version (in einer Header-Datei) mit Unterstützung für das Ändern mehrerer Bits (funktioniert übrigens auf AVR-Mikrocontrollern):
namespace bit {
template <typename T1, typename T2>
constexpr inline T1 bitmask(T2 bit)
{return (T1)1 << bit;}
template <typename T1, typename T3, typename ...T2>
constexpr inline T1 bitmask(T3 bit, T2 ...bits)
{return ((T1)1 << bit) | bitmask<T1>(bits...);}
/** Set these bits (others retain their state) */
template <typename T1, typename ...T2>
constexpr inline void set (T1 &variable, T2 ...bits)
{variable |= bitmask<T1>(bits...);}
/** Set only these bits (others will be cleared) */
template <typename T1, typename ...T2>
constexpr inline void setOnly (T1 &variable, T2 ...bits)
{variable = bitmask<T1>(bits...);}
/** Clear these bits (others retain their state) */
template <typename T1, typename ...T2>
constexpr inline void clear (T1 &variable, T2 ...bits)
{variable &= ~bitmask<T1>(bits...);}
/** Flip these bits (others retain their state) */
template <typename T1, typename ...T2>
constexpr inline void flip (T1 &variable, T2 ...bits)
{variable ^= bitmask<T1>(bits...);}
/** Check if any of these bits are set */
template <typename T1, typename ...T2>
constexpr inline bool isAnySet(const T1 &variable, T2 ...bits)
{return variable & bitmask<T1>(bits...);}
/** Check if all these bits are set */
template <typename T1, typename ...T2>
constexpr inline bool isSet (const T1 &variable, T2 ...bits)
{return ((variable & bitmask<T1>(bits...)) == bitmask<T1>(bits...));}
/** Check if all these bits are not set */
template <typename T1, typename ...T2>
constexpr inline bool isNotSet (const T1 &variable, T2 ...bits)
{return ((variable & bitmask<T1>(bits...)) != bitmask<T1>(bits...));}
}
Beispiel für die Verwendung:
#include <iostream>
#include <bitset> // for console output of binary values
// and include the code above of course
using namespace std;
int main() {
uint8_t v = 0b1111'1100;
bit::set(v, 0);
cout << bitset<8>(v) << endl;
bit::clear(v, 0,1);
cout << bitset<8>(v) << endl;
bit::flip(v, 0,1);
cout << bitset<8>(v) << endl;
bit::clear(v, 0,1,2,3,4,5,6,7);
cout << bitset<8>(v) << endl;
bit::flip(v, 0,7);
cout << bitset<8>(v) << endl;
}
BTW: Es stellt sich heraus, dass constexpr und inline nicht verwendet werden, wenn das Optimierungsargument (z.B.: -O3) nicht an den Compiler gesendet wird. Probieren Sie den Code einfach aus unter https://godbolt.org/ und sehen Sie sich die ASM-Ausgabe an.
Dieses Programm basiert auf der obigen Lösung von @Jeremy. Wenn jemand schnell herumspielen möchte.
public class BitwiseOperations {
public static void main(String args[]) {
setABit(0, 4); // set the 4th bit, 0000 -> 1000 [8]
clearABit(16, 5); // clear the 5th bit, 10000 -> 00000 [0]
toggleABit(8, 4); // toggle the 4th bit, 1000 -> 0000 [0]
checkABit(8,4); // check the 4th bit 1000 -> true
}
public static void setABit(int input, int n) {
input = input | ( 1 << n-1);
System.out.println(input);
}
public static void clearABit(int input, int n) {
input = input & ~(1 << n-1);
System.out.println(input);
}
public static void toggleABit(int input, int n) {
input = input ^ (1 << n-1);
System.out.println(input);
}
public static void checkABit(int input, int n) {
boolean isSet = ((input >> n-1) & 1) == 1;
System.out.println(isSet);
}
}
Output :
8
0
0
true
Hier ist eine Routine in C, um die grundlegenden bitweisen Operationen durchzuführen:
#define INT_BIT (unsigned int) (sizeof(unsigned int) * 8U) //number of bits in unsigned int
int main(void)
{
unsigned int k = 5; //k is the bit position; here it is the 5th bit from the LSb (0th bit)
unsigned int regA = 0x00007C7C; //we perform bitwise operations on regA
regA |= (1U << k); //Set kth bit
regA &= ~(1U << k); //Clear kth bit
regA ^= (1U << k); //Toggle kth bit
regA = (regA << k) | regA >> (INT_BIT - k); //Rotate left by k bits
regA = (regA >> k) | regA << (INT_BIT - k); //Rotate right by k bits
return 0;
}
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)