Pregunta ¿Cómo configura, borra y alterna un solo bit?


¿Cómo se configura, se borra y se alterna un poco en C / C ++?


2048
2017-09-07 00:42


origen


Respuestas:


Configurando un poco

Use el operador O bit a bit (|) para establecer un poco.

number |= 1UL << n;

Eso establecerá el nun poco de number.

Utilizar 1ULL Si number es más ancho que unsigned long; Promoción de 1UL << n no sucede hasta después de evaluar 1UL << n donde su comportamiento indefinido es cambiar por más que el ancho de un long. Lo mismo se aplica a todos los demás ejemplos.

Despejando un poco

Use el operador AND bit a bit (&) para aclarar un poco.

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

Eso borrará el nun poco de number. Debe invertir la cadena de bits con el operador NOT bit a bit (~), luego Y.

Alternar un poco

El operador XOR (^) se puede usar para alternar un poco.

number ^= 1UL << n;

Eso alternará nun poco de number.

Comprobando un poco

Usted no pidió esto, pero también podría agregarlo.

Para verificar un poco, cambie el número n a la derecha, luego en bit Y Y:

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

Eso pondrá el valor de la nun poco de number en la variable bit.

Cambiando el norteth bit to X

Configurando el nth bit a cualquiera 1 o 0 se puede lograr con lo siguiente en una implementación C ++ con complemento a 2:

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

Poco n se establecerá si x es 1y borrado si x es 0. Si x tiene algún otro valor, obtienes basura. x = !!x lo booleanizará a 0 o 1.

Para hacer esto independiente del comportamiento de negación del complemento de 2 (donde -1 tiene todos los bits configurados, a diferencia de un complemento de 1 o una implementación de signo / magnitud de C ++), use la negación sin signo.

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

o

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

En general, es una buena idea utilizar tipos sin signo para la manipulación de bits portátil.

En general, también es una buena idea no copiar / pegar código en general y mucha gente usa macros de preprocesador (como la comunidad wiki responde más abajo) o algún tipo de encapsulación.


2997
2017-09-07 00:50



Usando la biblioteca estándar de C ++: std::bitset<N>.

O el Aumentar versión: boost::dynamic_bitset.

No es necesario que hagas tu propio:

#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 versión de Boost permite un conjunto de bits de tiempo de ejecución en comparación con un biblioteca estándar conjunto de bits del tamaño de compilación.


381
2017-09-18 00:34



La otra opción es usar campos de bit:

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

struct bits mybits;

define un campo de 3 bits (en realidad, son tres campos de 1 bit). Las operaciones de bits ahora se vuelven un poco (jaja) más simples:

Para establecer o borrar un bit:

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

Para alternar un poco:

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

Comprobando un poco:

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

Esto solo funciona con campos de bits de tamaño fijo. De lo contrario, debe recurrir a las técnicas de intercambio de bits descritas en publicaciones anteriores.


212
2017-09-11 00:56



Utilizo las macros definidas en un archivo de cabecera para manejar el conjunto de bits y borrar:

/* 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 veces vale la pena usar un enum a nombre los bits:

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

Luego usa el nombres mas tarde. Es decir. escribir

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

para establecer, borrar y probar. De esta manera ocultas los números mágicos del resto de tu código.

Aparte de eso, respaldo la solución de Jeremy.


99
2017-09-17 02:04



De 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, analicemos las cosas ...

La expresión común con la que parece tener problemas en todos estos es "(1L << (posn))". Todo lo que hace es crear una máscara con un solo bit en y que funcionará con cualquier tipo de entero. El argumento "posn" especifica el posición donde quieres el bit. Si posn == 0, entonces esta expresión evaluar a:

    0000 0000 0000 0000 0000 0000 0000 0001 binary.

Si posn == 8, evaluará a

    0000 0000 0000 0000 0000 0001 0000 0000 binary.

En otras palabras, simplemente crea un campo de 0 con un 1 en el especificado posición. La única parte difícil es en la macro BitClr () donde tenemos que establecer un solo bit de 0 en un campo de 1. Esto se logra mediante el uso de los 1 complemento de la misma expresión indicada por el operador tilde (~).

Una vez que se crea la máscara, se aplica al argumento tal como sugiere, mediante el uso de los operadores bit a bit y (&), o (|) y xor (^). Desde la máscara es de tipo largo, las macros funcionarán igual de bien en char's, short's, int's, o largo.

La conclusión es que esta es una solución general para toda una clase de problemas. Por supuesto, es posible e incluso apropiado reescribir el equivalente a cualquiera de estas macros con valores de máscara explícitos cada vez que Necesito uno, pero ¿por qué hacerlo? Recuerde, la sustitución de macro ocurre en el preprocesador y, por lo tanto, el código generado reflejará el hecho de que los valores se consideran constantes por el compilador, es decir, es igual de eficiente de usar las macros generalizadas en cuanto a "reinventar la rueda" cada vez que necesita hacer manipulación de bits.

¿No está convencido? Aquí hay un código de prueba: utilicé Watcom C con optimización completa y sin usar _cdecl para que el desensamblaje resultante sea tan limpio como posible:

---- [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 (desarmado)] -------------------------------------- ---------

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

---- [finis] ------------------------------------------- ----------------------


34
2018-06-05 14:18



Para el principiante me gustaría explicar un poco más con un ejemplo:

Ejemplo:

value is 0x55;
bitnum : 3rd.

los & operador se utiliza verificar el 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)

Alternar o Voltear:

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

| operador: establecer el bit

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

28
2017-09-07 00:45



Use los operadores bit a bit: &  | 

Para establecer el último bit en 000b:

foo = foo | 001b

Para verificar el último bit en foo:

if ( foo & 001b ) ....

Para borrar el último bit en foo:

foo = foo & 110b

solía XXXb para mayor claridad. Probablemente esté trabajando con representación HEX, dependiendo de la estructura de datos en la que está empaquetando bits.


26
2017-07-13 06:53