Domanda Come impostare, cancellare e attivare un singolo bit?


Come si imposta, si cancella e si imposta un bit in C / C ++?


2048
2017-09-07 00:42


origine


risposte:


Impostazione un po '

Utilizzare l'operatore OR bit a bit (|) per impostare un po '.

number |= 1UL << n;

Questo imposterà il nun po 'di number.

Uso 1ULL Se number è più largo di unsigned long; promozione di 1UL << n non succede fino a dopo aver valutato 1UL << n dove è il comportamento indefinito a spostarsi di più della larghezza di a long. Lo stesso vale per tutti gli altri esempi.

Schiarirsi un po '

Utilizzare l'operatore AND bit a bit (&) per cancellare un po '.

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

Questo cancellerà il nun po 'di number. È necessario invertire la stringa di bit con l'operatore NOT bit a bit (~), quindi AND it.

Toggling un po '

L'operatore XOR (^) può essere utilizzato per alternare un bit.

number ^= 1UL << n;

Ciò cambierà il nun po 'di number.

Controllando un po '

Non l'hai chiesto, ma potrei anche aggiungerlo.

Per controllare un bit, sposta il numero n a destra, poi a bit AND:

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

Questo metterà il valore del nun po 'di number nella variabile bit.

Cambiare il nun po 'a X

Impostazione del nun po 'per entrambi 1 o 0 può essere ottenuto con quanto segue sull'implementazione C ++ del complemento a 2:

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

Po n sarà impostato se x è 1e cancellato se x è 0. Se x ha qualche altro valore, ottieni spazzatura. x = !!x la booleanizzerà a 0 o 1.

Per renderlo indipendente dal comportamento di negazione del complemento a 2 (dove -1 ha tutti i bit impostati, diversamente dall'implementazione di un complemento 1 o di C ++ di tipo sign / magnitude), usa la negazione senza segno.

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

o

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

In genere è consigliabile utilizzare tipi non firmati per la manipolazione di bit portatili.

In genere è anche una buona idea non copiare / incollare il codice in generale e così tante persone usano macro preprocessore (come la community wiki risponde più in basso) o una sorta di incapsulamento.


2995
2017-09-07 00:50



Utilizzando la libreria standard C ++: std::bitset<N>.

O il Incremento versione: boost::dynamic_bitset.

Non è necessario eseguire il rollover:

#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

La versione Boost consente un set di bit di runtime comparato con a libreria standard bitset di dimensioni in fase di compilazione.


380
2017-09-18 00:34



L'altra opzione è usare i campi di bit:

struct bits {
    unsigned int a:1;
    unsigned int b:1;
    unsigned int c:1;
};

struct bits mybits;

definisce un campo a 3 bit (in realtà, si tratta di tre campi a 1 bit). Le operazioni bit ora diventano un po '(haha) più semplici:

Per impostare o cancellare un po ':

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

Per cambiare un po ':

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

Controllando un po ':

if (mybits.c)  //if mybits.c is non zero the next line below will execute

Funziona solo con campi di bit a dimensione fissa. Altrimenti devi ricorrere alle tecniche di manipolazione dei bit descritte nei post precedenti.


212
2017-09-11 00:56



Uso le macro definite in un file di intestazione per gestire i bit impostati e deselezionare:

/* 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)))

/* x=target variable, y=mask */
#define BITMASK_SET(x,y) ((x) |= (y))
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
#define BITMASK_FLIP(x,y) ((x) ^= (y))
#define BITMASK_CHECK_ALL(x,y) (((x) & (y)) == (y))   // warning: evaluates y twice
#define BITMASK_CHECK_ANY(x,y) ((x) & (y))

125
2017-09-08 21:07



A volte vale la pena usare un enum a nome i bit:

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

Quindi utilizzare il nomi più tardi. Cioè Scrivi

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

per impostare, cancellare e testare. In questo modo nascondi i numeri magici dal resto del tuo codice.

A parte questo, appoggio la soluzione di Jeremy.


99
2017-09-17 02:04



A partire dal snip-c.zipbitops.h:

/*
**  Bit set, clear, and test operations
**
**  public domain snippet by Bob Stout
*/

typedef enum {ERROR = -1, FALSE, TRUE} LOGICAL;

#define BOOL(x) (!(!(x)))

#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))

OK, analizziamo le cose ...

L'espressione comune con cui sembra che tu abbia problemi in tutti questi è "(1L << (posn))". Tutto ciò che fa è creare una maschera con un singolo bit e che funzionerà con qualsiasi tipo intero. L'argomento "posn" specifica il posiziona dove vuoi il bit. Se posn == 0, allora questa espressione lo farà valutare a:

    0000 0000 0000 0000 0000 0000 0000 0001 binary.

Se posn == 8, valuterà a

    0000 0000 0000 0000 0000 0001 0000 0000 binary.

In altre parole, crea semplicemente un campo di 0 con un 1 al valore specificato posizione. L'unica parte difficile è nella macro BitClr () in cui dobbiamo impostare un singolo 0 bit in un campo di 1. Questo si ottiene usando gli 1 complemento della stessa espressione indicata dall'operatore tilde (~).

Una volta creata la maschera, viene applicata all'argomento proprio come suggerisci, usando gli operatori bitwise e (&), o (|), e xor (^). Poiché la maschera è di tipo lungo, le macro funzioneranno altrettanto bene su char's, short's, int's, o di lunga durata.

La linea di fondo è che questa è una soluzione generale per un'intera classe di i problemi. È, ovviamente, possibile ed anche appropriato riscrivere il equivalente di una di queste macro con valori di maschera espliciti ogni volta che si ne hai bisogno, ma perché farlo? Ricorda, la sostituzione delle macro avviene nel preprocessore e quindi il codice generato rifletterà il fatto che i valori sono considerati costanti dal compilatore - cioè è altrettanto efficiente da usare i macro generalizzati come "reinventare la ruota" ogni volta che è necessario manipolazione bit.

Poco convinta? Ecco alcuni codici di test: ho usato Watcom C con ottimizzazione completa e senza usare _cdecl in modo che lo smontaggio risultante sia pulito come possibile:

---- [TEST.C] ----------------------------------------- -----------------------

#define BOOL(x) (!(!(x)))

#define BitSet(arg,posn) ((arg) | (1L << (posn)))
#define BitClr(arg,posn) ((arg) & ~(1L << (posn)))
#define BitTst(arg,posn) BOOL((arg) & (1L << (posn)))
#define BitFlp(arg,posn) ((arg) ^ (1L << (posn)))

int bitmanip(int word)
{
      word = BitSet(word, 2);
      word = BitSet(word, 7);
      word = BitClr(word, 3);
      word = BitFlp(word, 9);
      return word;
}

---- [TEST.OUT (smontato)] -------------------------------------- ---------

Module: C:\BINK\tst.c
Group: 'DGROUP' CONST,CONST2,_DATA,_BSS

Segment: _TEXT  BYTE   00000008 bytes  
 0000  0c 84             bitmanip_       or      al,84H    ; set bits 2 and 7
 0002  80 f4 02                          xor     ah,02H    ; flip bit 9 of EAX (bit 1 of AH)
 0005  24 f7                             and     al,0f7H
 0007  c3                                ret     

No disassembly errors

---- [fine] ------------------------------------------- ----------------------


34
2018-06-05 14:18



Per il principiante vorrei spiegare un po 'di più con un esempio:

Esempio:

value is 0x55;
bitnum : 3rd.

Il & viene utilizzato l'operatore controlla il bit:

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)

Attiva o capovolgi:

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

| operatore: imposta il bit

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

28
2017-09-07 00:45



Utilizzare gli operatori bit a bit: &  | 

Per impostare l'ultimo bit in 000b:

foo = foo | 001b

Per controllare l'ultimo bit in foo:

if ( foo & 001b ) ....

Per cancellare l'ultimo bit in foo:

foo = foo & 110b

ero solito XXXb per chiarezza. Probabilmente lavorerai con la rappresentazione HEX, a seconda della struttura dei dati in cui stai impacchettando i bit.


26
2017-07-13 06:53



Ecco la mia macro aritmetica bit preferita, che funziona per qualsiasi tipo di matrice di numeri interi senza segno unsigned char fino a size_t (che è il tipo più grande che dovrebbe essere efficiente con cui lavorare):

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

Per impostare un po ':

BITOP(array, bit, |=);

Per chiarire un po ':

BITOP(array, bit, &=~);

Per cambiare un po ':

BITOP(array, bit, ^=);

Per testare un po ':

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

eccetera.


24
2018-06-14 15:23