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

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

Configurando un poco

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

 number |= 1UL << n; 

Eso establecerá el n ésimo bit de number .

Use 1ULL si el number es más ancho que el unsigned long ; la promoción de 1UL << n no ocurre hasta después de evaluar 1UL << n cuando su comportamiento indefinido cambia más allá del 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 borrar un bit.

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

Eso borrará el enésimo bit de number . Debe invertir la cadena de bits con el operador NOT bit a bit ( ~ ), y luego Y.

Alternar un poco

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

 number ^= 1UL << n; 

Eso alternará el n ésimo bit 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 del n ésimo bit de number en el bit variable.

Cambiar el n- ésimo bit a x

Establecer el n ésimo bit a 1 o 0 se puede lograr con lo siguiente en una implementación de C ++ con complemento a 2:

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

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

Para que esto sea 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 respuesta wiki de la comunidad más abajo ) o algún tipo de encapsulación.

Uso de la biblioteca estándar de C ++: std::bitset .

O la versión de Boost : boost::dynamic_bitset .

No es necesario que hagas tu propio:

 #include  #include  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 conjunto de bits de tamaño de comstackción de biblioteca estándar .

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.

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

A veces vale la pena usar una enum para nombrar los bits:

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

Luego usa los nombres más adelante. Es decir,

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

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

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

De snip-c.zip ‘s bitops.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 activado y que funcionará con cualquier tipo de entero. El argumento "posn" especifica la posición donde desea el bit. Si posn == 0, esta expresión se 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 la posición especificada. La única parte difícil es en la macro BitClr () donde tenemos que establecer un único bit de 0 en un campo de 1. Esto se logra utilizando el complemento de 1 de la misma expresión que denota el operador de tilde (~).

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

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 de cualquiera de estas macros con valores de máscara explícitos cada vez que lo necesite, pero ¿por qué hacerlo? Recuerde, la sustitución de macro ocurre en el preprocesador y el código generado reflejará el hecho de que los valores son considerados constantes por el comstackdor, es decir, es tan eficiente usar las macros generalizadas como "reinventar la rueda" cada vez que necesite hacer la 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, por lo que el desensamblaje resultante sería lo más limpio 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] ------------------------------------------- ----------------------

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

Ejemplo:

 value is 0x55; bitnum : 3rd. 

El operador & se utiliza para 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) 

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 

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

Esta es mi macro aritmética de bit favorita, que funciona para cualquier tipo de matriz de enteros sin signo desde unsigned char hasta size_t (que es el tipo más grande con el que debería trabajarse de manera eficiente):

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

Para establecer un bit:

 BITOP(array, bit, |=); 

Para borrar un poco:

 BITOP(array, bit, &=~); 

Para alternar un poco:

 BITOP(array, bit, ^=); 

Para probar un poco:

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

etc.

Como está etiquetado como “incrustado”, supongo que está utilizando un microcontrolador. Todas las sugerencias anteriores son válidas y funcionan (leer-modificar-escribir, uniones, estructuras, etc.).

Sin embargo, durante un ataque de depuración basado en osciloscopios, me sorprendió descubrir que estos métodos tienen una sobrecarga considerable en los ciclos de CPU en comparación con escribir un valor directamente en los registros PORTnSET / PORTnCLEAR de la micro, lo que hace una verdadera diferencia cuando hay ciclos ajustados / altos -frecuencia de pernos de conmutación ISR.

Para los que no están familiarizados: en mi ejemplo, el micro tiene un registro de estado de pines general PORTn que refleja los pines de salida, por lo que hacer PORTn | = BIT_TO_SET da como resultado una lectura-modificación-escritura en ese registro. Sin embargo, los registros PORTnSET / PORTnCLEAR toman ‘1’ para significar “por favor haga este bit 1” (SET) o “por favor haga que este bit sea cero” (CLEAR) y un ‘0’ para significar “dejar el pin solo”. entonces, terminas con dos direcciones de puertos dependiendo de si estás configurando o borrando el bit (no siempre es conveniente), sino de una reacción mucho más rápida y un código ensamblado más pequeño.

El enfoque de campo de bits tiene otras ventajas en el campo incrustado. Puede definir una estructura que se asigna directamente a los bits en un registro de hardware particular.

 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; 

Debe conocer la orden de empaquetado de bits; creo que es MSB primero, pero esto puede depender de la implementación. Además, verifique cómo los campos de los manejadores de comstackdores cruzan los límites de bytes.

Luego puede leer, escribir, probar los valores individuales como antes.

Más general, para bitmaps de tamaño arbitrario:

 #define BITS 8 #define BIT_SET( p, n) (p[(n)/BITS] |= (0x80>>((n)%BITS))) #define BIT_CLEAR(p, n) (p[(n)/BITS] &= ~(0x80>>((n)%BITS))) #define BIT_ISSET(p, n) (p[(n)/BITS] & (0x80>>((n)%BITS))) 

Compruebe un bit en una ubicación arbitraria en una variable de tipo arbitrario:

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

Uso de muestra:

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

Notas: Esto está diseñado para ser rápido (dada su flexibilidad) y no ramificado. Resulta en un código de máquina SPARC eficiente cuando se comstack Sun Studio 8; También lo probé usando MSVC ++ 2008 en amd64. Es posible crear macros similares para establecer y borrar bits. La diferencia clave de esta solución en comparación con muchos otros aquí es que funciona para cualquier ubicación en casi cualquier tipo de variable.

Si estás jugando un poco, es posible que quieras usar máscaras que harán que todo sea más rápido. Las siguientes funciones son muy rápidas y aún flexibles (permiten que los bits se muevan en mapas de bits de cualquier tamaño).

 const unsigned char TQuickByteMask[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, }; /** Set bit in any sized bit mask. * * @return none * * @param bit - Bit number. * @param bitmap - Pointer to bitmap. */ void TSetBit( short bit, unsigned char *bitmap) { short n, x; x = bit / 8; // Index to byte. n = bit % 8; // Specific bit in byte. bitmap[x] |= TQuickByteMask[n]; // Set bit. } /** Reset bit in any sized mask. * * @return None * * @param bit - Bit number. * @param bitmap - Pointer to bitmap. */ void TResetBit( short bit, unsigned char *bitmap) { short n, x; x = bit / 8; // Index to byte. n = bit % 8; // Specific bit in byte. bitmap[x] &= (~TQuickByteMask[n]); // Reset bit. } /** Toggle bit in any sized bit mask. * * @return none * * @param bit - Bit number. * @param bitmap - Pointer to bitmap. */ void TToggleBit( short bit, unsigned char *bitmap) { short n, x; x = bit / 8; // Index to byte. n = bit % 8; // Specific bit in byte. bitmap[x] ^= TQuickByteMask[n]; // Toggle bit. } /** Checks specified bit. * * @return 1 if bit set else 0. * * @param bit - Bit number. * @param bitmap - Pointer to bitmap. */ short TIsBitSet( short bit, const unsigned char *bitmap) { short n, x; x = bit / 8; // Index to byte. n = bit % 8; // Specific bit in byte. // Test bit (logigal AND). if (bitmap[x] & TQuickByteMask[n]) return 1; return 0; } /** Checks specified bit. * * @return 1 if bit reset else 0. * * @param bit - Bit number. * @param bitmap - Pointer to bitmap. */ short TIsBitReset( short bit, const unsigned char *bitmap) { return TIsBitSet(bit, bitmap) ^ 1; } /** Count number of bits set in a bitmap. * * @return Number of bits set. * * @param bitmap - Pointer to bitmap. * @param size - Bitmap size (in bits). * * @note Not very efficient in terms of execution speed. If you are doing * some computationally intense stuff you may need a more complex * implementation which would be faster (especially for big bitmaps). * See (http://graphics.stanford.edu/~seander/bithacks.html). */ int TCountBits( const unsigned char *bitmap, int size) { int i, count = 0; for (i=0; i 

Tenga en cuenta que para establecer el bit 'n' en un entero de 16 bits, haga lo siguiente:

 TSetBit( n, &my_int); 

Depende de usted asegurarse de que el número de bit esté dentro del rango del bitmap que pase. Tenga en cuenta que para los pequeños procesadores endian esos bytes, palabras, dwords, qwords, etc. se mapean correctamente en la memoria (razón principal por la que los pequeños procesadores endian son "mejores" que los procesadores big-endian, ah, siento que viene una guerra de llama en...).

Utilizar esta:

 int ToggleNthBit ( unsigned char n, int num ) { if(num & (1 << n)) num &= ~(1 << n); else num |= (1 << n); return num; } 

Este progtwig es para cambiar cualquier bit de datos de 0 a 1 o de 1 a 0:

 { 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< 

Ampliando la respuesta del conjunto de bitset :

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

Si desea realizar toda esta operación con progtwigción C en el kernel de Linux , le sugiero que use API estándar del kernel de Linux.

Ver https://www.kernel.org/doc/htmldocs/kernel-api/ch02s03.html

 set_bit Atomically set a bit in memory clear_bit Clears a bit in memory change_bit Toggle a bit in memory test_and_set_bit Set a bit and return its old value test_and_clear_bit Clear a bit and return its old value test_and_change_bit Change a bit and return its old value test_bit Determine whether a bit is set 

Nota: Aquí toda la operación ocurre en un solo paso. Por lo tanto, se garantiza que todos estos dispositivos son atómicos incluso en computadoras SMP y son útiles para mantener la coherencia entre los procesadores.

Visual C 2010, y tal vez muchos otros comstackdores, tienen soporte directo para operaciones de bits incorporadas. Sorprendentemente, esto funciona, incluso el operador sizeof () funciona correctamente.

 bool IsGph[256], IsNotGph[256]; // Initialize boolean array to detect printable characters for(i=0; i 

Por lo tanto, para su pregunta, IsGph [i] = 1, o IsGph [i] = 0 facilitan la configuración y el borrado de bools.

Para encontrar caracteres no imprimibles ...

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

Tenga en cuenta que no hay nada "especial" sobre este código. Se trata un poco como un entero, que técnicamente es. A 1 bit integer that can hold 2 values, and 2 values only.

I once used this approach to find duplicate loan records, where loan_number was the ISAM key, using the 6-digit loan number as an index into the bit array. Savagely fast, and after 8 months, proved that the mainframe system we were getting the data from was in fact malfunctioning. The simplicity of bit arrays makes confidence in their correctness very high - vs a searching approach for example.

Use one of the operators as defined here .

To set a bit, used int x = x | 0x?; where ? is the bit position in binary form.

Here are some macros I use:

 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) 

How do you set, clear, and toggle a single bit?

To address a common coding pitfall when attempting to form the mask:
1 is not always wide enough

What problems happen when number is a wider type than 1 ?
x may be too great for the shift 1 << x leading to undefined behavior (UB). Even if x is not too great, ~ may not flip enough most-significant-bits.

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

To insure 1 is wide enough:

Code could use 1ull or pedantically (uintmax_t)1 and let the compiler optimize.

 number |= (1ull << x); number |= ((uintmax_t)1 << x); 

Or cast - which makes for coding/review/maintenance issues keeping the cast correct and up-to-date.

 number |= (type_of_number)1 << x; 

Or gently promote the 1 by forcing a math operation that is as least as wide as the type of number .

 number |= (number*0 + 1) << x; 

As with most bit manipulations, best to work with unsigned types rather than signed ones

A C++11 templated version (put in a header):

 namespace bit { template  inline void set (T1 &variable, T2 bit) {variable |= ((T1)1 << bit);} template  inline void clear(T1 &variable, T2 bit) {variable &= ~((T1)1 << bit);} template  inline void flip (T1 &variable, T2 bit) {variable ^= ((T1)1 << bit);} template  inline bool test (T1 &variable, T2 bit) {return variable & ((T1)1 << bit);} } namespace bitmask { template  inline void set (T1 &variable, T2 bits) {variable |= bits;} template  inline void clear(T1 &variable, T2 bits) {variable &= ~bits;} template  inline void flip (T1 &variable, T2 bits) {variable ^= bits;} template  inline bool test_all(T1 &variable, T2 bits) {return ((variable & bits) == bits);} template  inline bool test_any(T1 &variable, T2 bits) {return variable & bits;} } 
 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 used

 int value, pos; 

value – Data
pos – position of the bit that we’re interested to set, clear or toggle
Set a bit

 value = value | 1 << pos; 

Clear a bit

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

Toggle a bit

 value = value ^ 1 << pos; 

Try one of these functions in the C language to change n bit:

 char bitfield; // Start at 0th position void chang_n_bit(int n, int value) { bitfield = (bitfield | (1 << n)) & (~( (1 << n) ^ (value << n) )); } 

O

 void chang_n_bit(int n, int value) { bitfield = (bitfield | (1 << n)) & ((value << n) | ((~0) ^ (1 << n))); } 

O

 void chang_n_bit(int n, int value) { if(value) bitfield |= 1 << n; else bitfield &= ~0 ^ (1 << n); } char get_n_bit(int n) { return (bitfield & (1 << n)) ? 1 : 0; } 

For setting BitIdx -th bit in Number to BitValue

 Number = Number xor (1 shl BitIdx) or (BitValue shl BitIdx) 

The trick here is to first unconditionally clear the BitIdx -th bit by xor-ing it with 1. This version seems slightly slower than the one with branching ( if bit = 1 then setbit else clearbit ) but is a one-liner.