¿Cómo se fija, se borra y se conmuta un bit?
Utiliza el operador OR a nivel de bits (|
) para fijar un bit.
number |= 1UL << n;
Esto establecerá el "n" bit de "número". n
debe ser cero, si desea establecer el 1
bit y así sucesivamente hasta n-1
, si desea establecer el n
bit.
Usa 1ULL
si number
es más ancho que unsigned long
; la promoción de 1UL << n
no ocurre hasta después de evaluar 1UL << n
donde es un comportamiento indefinido desplazar por más del ancho de un long
. Lo mismo se aplica al resto de los ejemplos.
Utiliza el operador AND a nivel de bits (&
) para borrar un bit.
number &= ~(1UL << n);
Esto borrará el n
bit de número
. Debes invertir la cadena de bits con el operador NOT a nivel de bits (~
), y luego AND.
El operador XOR (^
) se puede utilizar para cambiar un bit.
number ^= 1UL << n;
Esto cambiará el n
bit de número
.
No pediste esto, pero podría añadirlo.
Para comprobar un bit, se desplaza el número n a la derecha, y luego se hace un AND a nivel de bit:
bit = (number >> n) & 1U;
Eso pondrá el valor del n
ésimo bit de número
en la variable bit
.
Poner el n
ésimo bit a 1
o 0
se puede conseguir con lo siguiente en una implementación de C++ de complemento a 2:
number ^= (-x ^ number) & (1UL << n);
El bit n
se establece si x
es 1
, y se borra si x
es 0
. Si x
tiene algún otro valor, se obtiene basura. X = !! x` lo booleanizará a 0 o 1.
Para hacer esto independiente del comportamiento de la negación del complemento a 2 (donde -1
tiene todos los bits fijados, a diferencia de una implementación de C++ de complemento a 1 o de signo/magnitud), usa 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);
Por lo general, es una buena idea utilizar tipos sin signo para la manipulación portátil de bits.
o
number = (number & ~(1UL << n)) | (x << n);
(number & ~(1UL << n))
borrará el bit n
y (x << n)
pondrá el bit n
a x
.
También es una buena idea no copiar/pegar código en general y por eso mucha gente utiliza macros de preprocesador (como la respuesta de la wiki de la comunidad más abajo) o algún tipo de encapsulación.
A veces vale la pena utilizar un enum
para nombrar los bits:
enum ThingFlags = {
ThingMask = 0x0000,
ThingFlag0 = 1 << 0,
ThingFlag1 = 1 << 1,
ThingError = 1 << 8,
}
Luego, utilizar los nombres más adelante. Por ejemplo, escribir
thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}
para establecer, borrar y probar. De esta forma ocultas los números mágicos del resto de tu código.
Aparte de eso, apoyo la solución de Jeremy.
Utiliza los operadores "bitwise": &
|
Para poner el último bit en 000b
:
foo = foo | 001b
Para comprobar el último bit en foo
:
if ( foo & 001b ) ....
Para borrar el último bit de foo
:
foo = foo & 110b
He utilizado XXXb
para mayor claridad. Probablemente trabajarás con la representación HEX, dependiendo de la estructura de datos en la que estés empaquetando los bits.