c++ manipulation - Wie können Sie ein einzelnes Bit setzen, löschen und umschalten?




13 Answers

Ein bisschen einstellen

Verwenden Sie den bitweisen OR-Operator ( | ), um ein Bit festzulegen.

number |= 1UL << n;

Damit wird das n te Bit der number . n sollte Null sein, wenn Sie das 1 Bit usw. setzen möchten, bis n-1 , wenn Sie das n te Bit setzen möchten.

Verwenden Sie 1ULL wenn die number breiter als die unsigned long . Die Förderung von 1UL << n erfolgt erst, nachdem 1UL << n wobei es undefiniertes Verhalten ist, sich um mehr als die Breite eines long . Gleiches gilt für alle übrigen Beispiele.

Ein bisschen klären

Verwenden Sie den bitweisen AND-Operator ( & ), um ein wenig zu löschen.

number &= ~(1UL << n);

Dadurch wird das n te Bit number . Sie müssen den Bitstring mit dem bitweisen NOT-Operator ( ~ ) und dann mit AND invertieren.

Ein bisschen umschalten

Der XOR-Operator ( ^ ) kann verwendet werden, um ein Bit umzuschalten.

number ^= 1UL << n;

Dadurch wird das n te Bit der number umgeschaltet.

Ein bisschen überprüfen

Sie haben nicht danach gefragt, aber ich könnte es genauso gut hinzufügen.

Um etwas zu überprüfen, verschieben Sie die Zahl n nach rechts und dann bitweise UND:

bit = (number >> n) & 1U;

Dadurch wird der Wert des n ten Bits in das Variablenbit bit .

Ändern des n- ten Bits in x

Das Setzen des n ten Bits auf 1 oder 0 kann mit der folgenden Implementierung einer 2-er Komplement-C ++ - Implementierung erreicht werden:

number ^= (-x ^ number) & (1UL << n);

Bit n wird gesetzt, wenn x 1 , und gelöscht, wenn x 0 . Wenn x einen anderen Wert hat, erhalten Sie Müll. x = !!x booleanize es auf 0 oder 1.

Um dies vom Zweierkomplement-Negationsverhalten unabhängig zu machen (wobei bei -1 alle Bits gesetzt sind, im Gegensatz zu einer 1-Komplement- oder Vorzeichen- / Größen-C ++ - Implementierung), verwenden Sie die vorzeichenlose Negation.

number ^= (-(unsigned long)x ^ number) & (1UL << n);

oder

unsigned long newbit = !!x;    // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);

Im Allgemeinen ist es eine gute Idee, für die portable Bit-Bearbeitung unsignierte Typen zu verwenden.

Im Allgemeinen ist es auch eine gute Idee, Code im Allgemeinen nicht zu kopieren / einzufügen. Daher verwenden viele Leute Präprozessor-Makros (wie die Community-Wiki-Antwort weiter unten ) oder eine Art Verkapselung.

bitmaskierung multiple

Wie können Sie ein wenig in C / C ++ einstellen, löschen und umschalten?




Die andere Option 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). Bitoperationen werden jetzt etwas einfacher (haha):

Ein wenig setzen oder löschen:

mybits.b = 1;
mybits.c = 0;

Um ein wenig zu wechseln:

mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1;  /* all work */

Ein bisschen überprüfen:

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 den vorherigen Beiträgen beschriebenen Bit-Twiddling-Techniken zurückgreifen.




Manchmal ist es enum , die Bits mit einem enum zu benennen :

enum ThingFlags = {
  ThingMask  = 0x0000,
  ThingFlag0 = 1 << 0,
  ThingFlag1 = 1 << 1,
  ThingError = 1 << 8,
}

Verwenden Sie die Namen dann später. Ich schreibe

thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}

einstellen, löschen und testen. Auf diese Weise verstecken Sie die magischen Zahlen vor dem Rest Ihres Codes.

Abgesehen davon stimme ich Jeremys Lösung zu.




Für den Anfänger möchte ich mit einem Beispiel etwas mehr erklären:

Beispiel:

value is 0x55;
bitnum : 3rd.

Der Operator & wird verwendet, um das Bit zu überprüfen:

0101 0101
&
0000 1000
___________
0000 0000 (mean 0: False). It will work fine if the third bit is 1 (then the answer will be True)

Toggle oder Flip:

0101 0101
^
0000 1000
___________
0101 1101 (Flip the third bit without affecting other bits)

| Operator: das Bit setzen

0101 0101
|
0000 1000
___________
0101 1101 (set the third bit without affecting other bits)



Hier ist mein beliebtes Bit-Arithmetik-Makro, das für alle Arten von vorzeichenlosen Integer-Arrays von unsigned char bis zu size_t funktioniert (der größte Typ, mit dem man effizient arbeiten kann):

#define BITOP(a,b,op) \
 ((a)[(size_t)(b)/(8*sizeof *(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof *(a)))))

Um ein bisschen zu setzen:

BITOP(array, bit, |=);

Um etwas zu löschen:

BITOP(array, bit, &=~);

Um ein wenig zu wechseln:

BITOP(array, bit, ^=);

Um ein bisschen zu testen:

if (BITOP(array, bit, &)) ...

usw.




Der Bitfield-Ansatz hat weitere Vorteile in der Embedded-Arena. Sie können eine Struktur definieren, die direkt auf die Bits in einem bestimmten Hardware-Register abgebildet wird.

struct HwRegister {
    unsigned int errorFlag:1;  // one-bit flag field
    unsigned int Mode:3;       // three-bit mode field
    unsigned int StatusCode:4;  // four-bit status code
};

struct HwRegister CR3342_AReg;

Sie müssen sich der Reihenfolge der Bitpackung bewusst sein - ich denke, es ist zuerst MSB, aber dies kann von der Implementierung abhängen. Überprüfen Sie auch, wie die Felder Ihres Compilers Byte-Grenzen überschreiten.

Sie können dann die einzelnen Werte wie zuvor lesen, schreiben und testen.




Überprüfen Sie ein Bit an einer beliebigen Stelle in einer Variablen beliebigen Typs:

#define bit_test(x, y)  ( ( ((const char*)&(x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )

Verwendungsbeispiel:

int main(void)
{
    unsigned char arr[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };

    for (int ix = 0; ix < 64; ++ix)
        printf("bit %d is %d\n", ix, bit_test(arr, ix));

    return 0;
}

Hinweise: Dies ist darauf ausgelegt, schnell (aufgrund seiner Flexibilität) und nicht verzweigt zu sein. Es ergibt einen effizienten SPARC-Maschinencode, wenn Sun Studio 8 kompiliert wird. Ich habe es auch mit MSVC ++ 2008 auf amd64 getestet. Es ist möglich, ähnliche Makros zum Setzen und Löschen von Bits zu erstellen. Der Hauptunterschied dieser Lösung im Vergleich zu vielen anderen Lösungen besteht darin, dass sie für jeden Ort in nahezu allen Arten von Variablen funktioniert.




Dieses Programm kann jedes Datenbit von 0 auf 1 oder 1 auf 0 ändern:

{
    unsigned int data = 0x000000F0;
    int bitpos = 4;
    int bitvalue = 1;
    unsigned int bit = data;
    bit = (bit>>bitpos)&0x00000001;
    int invbitvalue = 0x00000001&(~bitvalue);
    printf("%x\n",bit);

    if (bitvalue == 0)
    {
        if (bit == 0)
            printf("%x\n", data);
        else
        {
             data = (data^(invbitvalue<<bitpos));
             printf("%x\n", data);
        }
    }
    else
    {
        if (bit == 1)
            printf("elseif %x\n", data);
        else
        {
            data = (data|(bitvalue<<bitpos));
            printf("else %x\n", data);
        }
    }
}



Die bitsetAntwort erweitern:

#include <iostream>
#include <bitset>
#include <string>

using namespace std;
int main() {
  bitset<8> byte(std::string("10010011");

  // Set Bit
  byte.set(3); // 10010111

  // Clear Bit
  byte.reset(2); // 10010101

  // Toggle Bit
  byte.flip(7); // 00010101

  cout << byte << endl;

  return 0;
}



Visual C 2010 und möglicherweise viele andere Compiler verfügen über eine direkte Unterstützung für integrierte Bitoperationen. Überraschenderweise funktioniert dies, auch wenn der Operator sizeof () ordnungsgemäß funktioniert.

bool    IsGph[256], IsNotGph[256];

//  Initialize boolean array to detect printable characters
for(i=0; i<sizeof(IsGph); i++)  {
    IsGph[i] = isgraph((unsigned char)i);
}

Also, zu Ihrer Frage machen IsGph [i] = 1 oder IsGph [i] = 0 das Setzen und Löschen von Bools einfach.

Nicht druckbare Zeichen finden ...

//  Initialize boolean array to detect UN-printable characters, 
//  then call function to toggle required bits true, while initializing a 2nd
//  boolean array as the complement of the 1st.
for(i=0; i<sizeof(IsGph); i++)  {
    if(IsGph[i])    {
         IsNotGph[i] = 0;
    }   else   {
         IsNotGph[i] = 1;
    }
}

Beachten Sie, dass an diesem Code nichts "Besonderes" ist. Es behandelt ein bisschen wie eine ganze Zahl - was technisch ist. Eine 1-Bit-Ganzzahl, die 2 Werte und nur 2 Werte aufnehmen kann.

Ich habe diesen Ansatz einmal verwendet, um doppelte Darlehenssätze zu finden, wobei loan_number der ISAM-Schlüssel war und die 6-stellige Darlehensnummer als Index für das Bit-Array verwendet. Schnell und nach acht Monaten bewies das Mainframe-System, von dem wir die Daten erhielten, tatsächlich nicht richtig. Die Einfachheit von Bit-Arrays macht das Vertrauen in ihre Korrektheit sehr hoch - im Vergleich zum Beispiel zum Suchen.




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)



int set_nth_bit(int num, int n){

    return (num | 1 << n);
}

int clear_nth_bit(int num, int n){

    return (num & ~( 1 << n));
}

int toggle_nth_bit(int num, int n){

    return num ^ (1 << n);
}

int check_nth_bit(int num, int n){

    return num & (1 << n);
}



Variable verwendet

int value, pos;

value -
Datenposition - Position des Bits, das wir setzen, löschen oder umschalten
möchten Bit setzen

value = value | 1 << pos;

Klar ein bisschen

value = value & ~(1 << pos); 

Ein wenig umschalten

value = value ^ 1 << pos;



Related