3165 Stimmen

Wie kann man ein einzelnes Bit setzen, löschen und umschalten?

Wie kann man ein Bit setzen, löschen und umschalten?

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.

5voto

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

4voto

sam msft Punkte 433

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)

3voto

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.

3voto

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

2voto

lckid2004 Punkte 21

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;   
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X