Use el operador OR a nivel de bit ( |) para establecer un bit.
number |=1UL<< n;
Eso establecerá el nth bit de number. ndebe ser cero, si desea establecer el 1bit st y así sucesivamente n-1, si desea establecer el nbit th.
Use 1ULLif numberes más ancho que unsigned long; la promoción de 1UL << nno ocurre hasta después de evaluar 1UL << ndónde es un comportamiento indefinido cambiar más de la anchura de a long. Lo mismo se aplica a todos los demás ejemplos.
Despejando un poco
Use el operador AND a nivel de bit ( &) para borrar un bit.
number &=~(1UL<< n);
Eso despejará la nparte 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á la parte de nth number.
Comprobando un poco
No pediste esto, pero también podría agregarlo.
Para verificar un bit, desplace el número n hacia la derecha, luego bit a bit Y:
bit =(number >> n)&1U;
Eso pondrá el valor del nth bit de numberen la variable bit.
Cambiar el n ésimo bit a x
Establecer el nbit th en cualquiera 1o 0se puede lograr con lo siguiente en una implementación C ++ del complemento a 2:
number ^=(-x ^ number)&(1UL<< n);
El bit nse establecerá si xes 1y se borrará si xes así 0. Si xtiene algún otro valor, obtienes basura. x = !!xlo booleanizará a 0 o 1.
Para que esto sea independiente del comportamiento de negación del complemento de 2 (donde -1tiene todos los bits establecidos, a diferencia de un complemento de 1 o implementación de signo / magnitud C ++), use la negación sin signo.
number ^=(-(unsignedlong)x ^ number)&(1UL<< n);
o
unsignedlong newbit =!!x;// Also booleanize to force 0 or 1
number ^=(-newbit ^ number)&(1UL<< n);
En general, es una buena idea usar tipos sin signo para la manipulación de bits portátil.
o
number =(number &~(1UL<< n))|(x << n);
(number & ~(1UL << n))borrará el nbit th y (x << n)establecerá el nbit th en x.
También es generalmente una buena idea no copiar / pegar código en general, y muchas personas usan macros de preprocesador (como la respuesta de la wiki de la comunidad más abajo ) o algún tipo de encapsulación.
Me gustaría señalar que en las plataformas que tienen soporte nativo para bit set / clear (por ejemplo, microcontroladores AVR), los compiladores a menudo traducirán 'myByte | = (1 << x)' en las instrucciones nativas de set / bit bit siempre que x sea una constante, por ejemplo: (1 << 5), o constante sin signo x = 5.
Aaron
52
bit = número & (1 << x); no pondrá el valor de bit x en bit a menos que el bit tenga el tipo _Bool (<stdbool.h>). De lo contrario, bit = !! (número & (1 << x)); will ..
Chris Young
23
por qué no cambias el último abit = (number >> x) & 1
aaronman
42
1es un intliteral, que está firmado. Entonces, todas las operaciones aquí operan con números firmados, que no están bien definidos por los estándares. Los estándares no garantizan el complemento de dos o el cambio aritmético, por lo que es mejor usarlo 1U.
Siyuan Ren
50
Prefiero number = number & ~(1 << n) | (x << n);cambiar el enésimo bit a x.
La versión Boost permite un conjunto de bits de tamaño de tiempo de ejecución en comparación con un conjunto de bits de tamaño de compilación de biblioteca estándar .
+1. No es que std :: bitset se pueda usar desde "C", pero como el autor etiquetó su pregunta con "C ++", AFAIK, su respuesta es la mejor por aquí ... std :: vector <bool> es otra forma, si uno sabe sus pros y sus contras
paercebal
23
@andrewdotnich: vector <bool> es (desafortunadamente) una especialización que almacena los valores como bits. Ver gotw.ca/publications/mill09.htm para más información ...
Niklas
71
Tal vez nadie lo mencionó porque esto fue etiquetado como incrustado. En la mayoría de los sistemas integrados, evitas STL como la peste. Y es probable que el soporte de impulso sea un ave muy rara para detectar entre la mayoría de los compiladores integrados.
Lundin
17
@ Martin Es muy cierto. Además de los asesinos específicos de rendimiento como STL y plantillas, muchos sistemas integrados incluso evitan completamente las bibliotecas estándar completas, porque es muy difícil de verificar. La mayor parte de la rama incrustada está adoptando estándares como MISRA, que requiere herramientas de análisis de código estático (cualquier profesional de software debería usar tales herramientas por cierto, no solo las personas incrustadas). En general, las personas tienen mejores cosas que hacer que ejecutar un análisis estático en toda la biblioteca estándar, si su código fuente está disponible para ellos en el compilador específico.
Lundin
37
@Lundin: Sus declaraciones son excesivamente amplias (por lo tanto, inútiles para discutir). Estoy seguro de que puedo encontrar situaciones en las que son ciertas. Esto no cambia mi punto inicial. Ambas clases están perfectamente bien para su uso en sistemas integrados (y sé con certeza que se usan). Su punto inicial acerca de que STL / Boost no se usa en sistemas integrados también es incorrecto. Estoy seguro de que hay sistemas que no los usan e incluso los sistemas que los usan se usan con prudencia, pero decir que no se usan simplemente no es correcto (porque hay sistemas en los que se usan).
define un campo de 3 bits (en realidad, son tres campos de 1 bit). Las operaciones de bit ahora se vuelven un poco (jaja) más simples:
Para establecer o borrar un poco:
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 cambio de bits descritas en publicaciones anteriores.
Siempre he encontrado que usar bitfields es una mala idea. No tiene control sobre el orden en que se asignan los bits (desde la parte superior o inferior), lo que hace que sea imposible serializar el valor de forma estable / portátil, excepto bit a la vez. También es imposible mezclar aritmética de bits de bricolaje con campos de bits, por ejemplo, hacer una máscara que pruebe varios bits a la vez. Por supuesto, puede usar && y esperar que el compilador lo optimice correctamente ...
R .. GitHub DEJE DE AYUDAR A ICE
34
Los campos de bits son malos de muchas maneras, casi podría escribir un libro al respecto. De hecho, casi tuve que hacer eso para un programa de campo de bits que necesitaba el cumplimiento de MISRA-C. MISRA-C exige que se documente todo el comportamiento definido por la implementación, por lo que terminé escribiendo un ensayo sobre todo lo que puede salir mal en los campos de bits. Orden de bits, endianess, bits de relleno, bytes de relleno, varios otros problemas de alineación, conversiones de tipo implícito y explícito hacia y desde un campo de bits, UB si no se usa int y así sucesivamente. En su lugar, utilice operadores bit a bit para menos errores y código portátil. Los campos de bits son completamente redundantes.
Lundin
44
Como la mayoría de las características del lenguaje, los campos de bits se pueden usar correctamente o se puede abusar de ellos. Si necesita empaquetar varios valores pequeños en un solo int, los campos de bits pueden ser muy útiles. Por otro lado, si comienza a hacer suposiciones sobre cómo los campos de bits se asignan al int que contiene real, solo está buscando problemas.
Ferruccio
44
@endolith: Esa no sería una buena idea. Podría hacerlo funcionar, pero no necesariamente sería portátil a un procesador diferente, a un compilador diferente o incluso a la próxima versión del mismo compilador.
Ferruccio
3
@Yasky y Ferruccio, obteniendo diferentes respuestas a sizeof () para este enfoque, deberían ilustrar los problemas de compatibilidad no solo entre los compiladores sino también a través del hardware. A veces nos engañamos a nosotros mismos de que hemos resuelto estos problemas con idiomas o tiempos de ejecución definidos, pero realmente se reduce a '¿funcionará en mi máquina?'. Ustedes incrustados tienen mi respeto (y simpatía).
Kelly S. French
181
Uso macros definidas en un archivo de encabezado 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))))// '!!' to make sure this returns 0 or 1/* 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))
Eh, me doy cuenta de que esta es una publicación de 5 años, pero no hay duplicación de argumentos en ninguna de esas macros, Dan
Robert Kelly
11
BITMASK_CHECK(x,y) ((x) & (y))debe ser de lo ((x) & (y)) == (y)contrario, devuelve un resultado incorrecto en la máscara multibit (ej. 5vs. 3) / * Hola a todos los sepultureros
:)
77
1debería ser (uintmax_t)1o similar en caso de que alguien intente usar estas macros en un longtipo o más grande
MM
2
BITMASK_CHECK_ALL(x,y)se puede implementar como!~((~(y))|(x))
Handy999
3
@ Handy999 Es un poco más fácil ver por qué eso funciona después de aplicar la ley de De Morgan y reorganizar para obtener!(~(x) & (y))
Tavian Barnes
114
A veces vale la pena usar un enumpara nombrar los bits:
Alternativamente, podría hacer una clearbits()función en lugar de &= ~. ¿Por qué estás usando una enumeración para esto? Pensé que eran para crear un montón de variables únicas con un valor arbitrario oculto, pero estás asignando un valor definido a cada una. Entonces, ¿cuál es el beneficio en comparación con solo definirlos como variables?
endolito
44
@endolith: El uso de enums para conjuntos de constantes relacionadas se remonta mucho en la programación de c. Sospecho que con los compiladores modernos, la única ventaja sobre, const shorto lo que sea, es que están agrupados explícitamente. Y cuando los quiere para algo más que máscaras de bits, obtiene la numeración automática. En c ++, por supuesto, también forman tipos distintos que le brindan un poco más de comprobación de errores estáticos.
dmckee --- ex-gatito moderador
Entrarás en constantes de enumeración indefinidas si no defines una constante para cada uno de los valores posibles de los bits. ¿Para qué enum ThingFlagssirve ThingError|ThingFlag1, por ejemplo?
Luis Colorado
66
Si utiliza este método, tenga en cuenta que las constantes de enumeración siempre son de tipo con signo int. Esto puede causar todo tipo de errores sutiles debido a la promoción de números enteros implícitos u operaciones bit a bit en tipos firmados. thingstate = ThingFlag1 >> 1invocará, por ejemplo, un comportamiento definido por la implementación. thingstate = (ThingFlag1 >> x) << ypuede invocar un comportamiento indefinido. Y así. Para estar seguro, utilice siempre un tipo sin signo.
Lundin
1
@Lundin: a partir de C ++ 11, puede establecer el tipo subyacente de una enumeración, por ejemplo: enum My16Bits: unsigned short { ... };
/*
** Bit set, clear, and test operations
**
** public domain snippet by Bob Stout
*/typedefenum{ERROR =-1, FALSE, TRUE} LOGICAL;#define BOOL(x)(!(!(x)))#defineBitSet(arg,posn)((arg)|(1L<<(posn)))#defineBitClr(arg,posn)((arg)&~(1L<<(posn)))#defineBitTst(arg,posn) BOOL((arg)&(1L<<(posn)))#defineBitFlp(arg,posn)((arg)^(1L<<(posn)))
OK, analicemos las cosas ...
La expresión común con la que parece estar teniendo problemas en todo esto es "(1L << (posn))". Todo lo que hace es crear una máscara con un solo bit y que funcionará con cualquier tipo de entero. El argumento "posn" especifica la posición donde desea el bit. Si posn == 0, entonces esta expresión se evaluará para:
00000000000000000000000000000001 binary.
Si posn == 8, se evaluará para:
00000000000000000000000100000000 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 necesitamos establecer un solo 0 bit en un campo de 1. Esto se logra utilizando el complemento de 1 de la misma expresión que denota el operador 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 (^). Como la máscara es de 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 macros ocurre en el preprocesador, por lo que el código generado reflejará el hecho de que el compilador considera que los valores son constantes, es decir, es tan eficiente usar las macros generalizadas como "reinventar la rueda" cada vez que necesite hacer manipulación de bits.
Poco convencido? Aquí hay un código de prueba: utilicé Watcom C con optimización completa y sin usar _cdecl, por lo que el desmontaje resultante sería lo más limpio posible:
#define BOOL(x)(!(!(x)))#defineBitSet(arg,posn)((arg)|(1L<<(posn)))#defineBitClr(arg,posn)((arg)&~(1L<<(posn)))#defineBitTst(arg,posn) BOOL((arg)&(1L<<(posn)))#defineBitFlp(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;}
Dos cosas sobre esto: (1) al examinar detenidamente sus macros, algunos pueden creer incorrectamente que las macros realmente establecen / borran / voltean los bits en el argumento, sin embargo no hay asignación; (2) su prueba.c no está completa; Sospecho que si ejecutara más casos encontraría un problema (ejercicio de lectura)
Dan
19
-1 Esto es simplemente una ofuscación extraña. Nunca reinventes el lenguaje C ocultando la sintaxis del lenguaje detrás de las macros, es una muy mala práctica. Luego, algunas rarezas: primero, 1L está firmado, lo que significa que todas las operaciones de bits se realizarán en un tipo firmado. Todo lo que se pasa a estas macros volverá como se firmó durante mucho tiempo. No está bien. En segundo lugar, esto funcionará de manera muy ineficiente en CPU más pequeñas, ya que se aplica durante mucho tiempo cuando las operaciones podrían haber estado en el nivel int. Tercero, las macros funcionales son la raíz de todo mal: no tienes ningún tipo de seguridad. Además, el comentario anterior sobre ninguna asignación es muy válido.
Lundin
2
Esto fallará si arges así long long. 1Lnecesita ser el tipo más amplio posible, entonces (uintmax_t)1. (Puede salirse con la suya 1ull)
MM
¿Optimizaste para el tamaño del código? En las CPU convencionales de Intel, obtendrá paradas de registro parcial al leer AX o EAX después de que esta función regrese, porque escribe los componentes de 8 bits de EAX. (Está bien en las CPU AMD u otras que no cambien el nombre de los registros parciales por separado del registro completo. Haswell / Skylake no cambian el nombre de AL por separado, pero cambian el nombre de AH ).
Peter Cordes
37
Use los operadores bit a bit: &|
Para configurar el último bit en 000b:
foo = foo |001b
Para comprobar el último bit en foo:
if( foo &001b)....
Para borrar el último bit en foo:
foo = foo &110b
Solía XXXbpor claridad. Probablemente trabajará con representación HEX, dependiendo de la estructura de datos en la que está empacando bits.
Aquí está mi macro aritmética de bits favorita, que funciona para cualquier tipo de matriz entera sin signo de unsigned charhasta size_t(que es el tipo más grande con el que debería ser eficiente trabajar):
#define BITOP(a,b,op) \
((a)[(size_t)(b)/(8*sizeof*(a))] op ((size_t)1<<((size_t)(b)%(8*sizeof*(a)))))
Es bueno leer, pero hay que tener en cuenta los posibles efectos secundarios. El uso BITOP(array, bit++, |=);en bucle probablemente no hará lo que la persona que llama desea.
miedo el
En efecto. =) Una variante que puede preferir es separarla en 2 macros, 1 para abordar el elemento de matriz y la otra para cambiar el bit a su lugar, ala BITCELL(a,b) |= BITMASK(a,b);(ambos toman acomo argumento para determinar el tamaño, pero este último nunca se evaluaría aya que aparece solo en sizeof).
R .. GitHub DEJA DE AYUDAR AL HIELO
1
@R .. Esta respuesta es muy antigua, pero probablemente prefiera una función a una macro en este caso.
PC Luddite
Menor: la tercera (size_t)elenco parece ser no sólo para asegurar cierta matemáticas sin firmar con %. Podría (unsigned)allí.
chux - Restablecer Monica
Lo (size_t)(b)/(8*sizeof *(a))innecesariamente podría reducirse bantes de la división. Solo un problema con matrices de bits muy grandes. Sigue siendo una macro interesante.
chux - Restablecer Monica
25
Como esto está etiquetado como "incrustado", supondré que está utilizando un microcontrolador. Todas las sugerencias anteriores son válidas y funcionan (lectura-modificación-escritura, uniones, estructuras, etc.).
Sin embargo, durante una serie de depuración basada en el osciloscopio, me sorprendió descubrir que estos métodos tienen una sobrecarga considerable en los ciclos de la CPU en comparación con escribir un valor directamente en los registros PORTnSET / PORTnCLEAR del micro, lo que hace una diferencia real cuando hay bucles estrechos / altos -frecuencia ISR pasadores de alternancia.
Para aquellos que no están familiarizados: en mi ejemplo, el micro tiene un registro general de estado de pin 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 un '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 "deje el pin en paz". entonces, terminas con dos direcciones de puerto dependiendo de si estás configurando o borrando el bit (no siempre es conveniente) pero una reacción mucho más rápida y un código ensamblado más pequeño.
Micro fue Coldfire MCF52259, usando C en Codewarrior. Mirar el desensamblador / asm es un ejercicio útil, ya que muestra todos los pasos que la CPU debe seguir para realizar incluso la operación más básica. <br> También vimos otras instrucciones de acaparamiento de CPU en bucles de tiempo crítico: restringir una variable haciendo var% = max_val cuesta una pila de ciclos de CPU cada vez, mientras que si (var> max_val) var- = max_val solo usa Un par de instrucciones. <br> Una buena guía para algunos trucos más está aquí: codeproject.com/Articles/6154/…
John U
Aún más importante, los registros auxiliares de E / S mapeados en memoria proporcionan un mecanismo para actualizaciones atómicas. Leer / modificar / escribir puede ir muy mal si se interrumpe la secuencia.
Ben Voigt
1
Tenga en cuenta que todos los registros de puertos se definirán como volatiley, por lo tanto, el compilador no puede realizar ninguna optimización en el código que involucra dichos registros. Por lo tanto, es una buena práctica desensamblar dicho código y ver cómo resultó a nivel de ensamblador.
Lundin
24
El enfoque de campo de bits tiene otras ventajas en el ámbito integrado. Puede definir una estructura que se asigne directamente a los bits en un registro de hardware particular.
structHwRegister{unsignedint errorFlag:1;// one-bit flag fieldunsignedintMode:3;// three-bit mode fieldunsignedintStatusCode:4;// four-bit status code};structHwRegister CR3342_AReg;
Debe tener en cuenta el orden de empaquetado de bits: creo que es MSB primero, pero esto puede depender de la implementación. Además, verifique cómo los manejadores del compilador cruzan los límites de bytes.
Luego puede leer, escribir, probar los valores individuales como antes.
Casi todo lo relacionado con los campos de bits está definido por la implementación. Incluso si logra encontrar todos los detalles sobre cómo su compilador particular los implementa, usarlos en su código seguramente lo hará no portátil.
Lundin
1
@Lundin: es cierto, pero el sistema embebido de bits del sistema (particularmente en los registros de hardware, a lo que se refiere mi respuesta) nunca será útil de todos modos.
Roddy
1
Tal vez no entre CPU completamente diferentes. Pero lo más probable es que desee que sea portátil entre compiladores y entre diferentes proyectos. Y hay muchos "ajustes de bits" incrustados que no están relacionados con el hardware, como la codificación / decodificación de protocolos de datos.
Lundin
... y si tiene la costumbre de usar campos de bits haciendo programación incrustada, encontrará que su código X86 se ejecuta más rápido y más ágil también. No en puntos de referencia simples donde tiene toda la máquina para aplastar el punto de referencia, sino en entornos de tareas múltiples del mundo real donde los programas compiten por los recursos. Ventaja CISC: cuyo objetivo de diseño original era compensar las CPU más rápido que los buses y la memoria lenta.
20
Marque un bit en una ubicación arbitraria en una variable de tipo arbitrario:
int main(void){unsignedchar 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));return0;}
Notas:
Esto está diseñado para ser rápido (dada su flexibilidad) y no ramificado. Da como resultado un código de máquina SPARC eficiente cuando se compila Sun Studio 8; También lo probé usando MSVC ++ 2008 en amd64. Es posible hacer macros similares para configurar y borrar bits. La diferencia clave de esta solución en comparación con muchas otras aquí es que funciona para cualquier ubicación en prácticamente cualquier tipo de variable.
Si está haciendo muchos giros, es posible que desee usar máscaras que harán que todo sea más rápido. Las siguientes funciones son muy rápidas y siguen siendo flexibles (permiten girar bits en mapas de bits de cualquier tamaño).
constunsignedcharTQuickByteMask[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.
*/voidTSetBit(short bit,unsignedchar*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.
*/voidTResetBit(short bit,unsignedchar*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.
*/voidTToggleBit(short bit,unsignedchar*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.
*/shortTIsBitSet(short bit,constunsignedchar*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])return1;return0;}/** Checks specified bit.
*
* @return 1 if bit reset else 0.
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/shortTIsBitReset(short bit,constunsignedchar*bitmap){returnTIsBitSet(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).
*/intTCountBits(constunsignedchar*bitmap,int size){int i, count =0;for(i=0; i<size; i++)if(TIsBitSet(i, bitmap))
count++;return count;}
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 bits esté dentro del rango del mapa de bits que pasa. Tenga en cuenta que para los pequeños procesadores endian que bytes, palabras, dwords, qwords, etc., se asignan correctamente entre sí en la memoria (razón principal de que los pequeños procesadores endian son "mejores" que los procesadores big endian, ah, siento que se acerca una guerra de llamas en...).
No use una tabla para una función que pueda implementarse con un solo operador. TQuickByteMask [n] es equivalente a (1 << n). Además, hacer sus argumentos cortos es una muy mala idea. El / y el% será en realidad una división, no un desplazamiento de bits / bit a bit y, porque la división con signo por una potencia de 2 no puede implementarse bit a bit. Debe hacer que el argumento escriba unsigned int!
R .. GitHub DEJA DE AYUDAR AL HIELO
¿Qué sentido tiene esto? ¿Solo hace que el código sea más lento y difícil de leer? No puedo ver una sola ventaja con eso. 1u << n es más fácil de leer para los programadores de C, y con suerte se puede traducir en una instrucción de CPU de un solo reloj. Su división, por otro lado, se traducirá en algo alrededor de 10 tics, o incluso tan mal como hasta 100 ticks, dependiendo de qué tan mal maneje la división la arquitectura específica. En cuanto a la función de mapa de bits, tendría más sentido tener una tabla de búsqueda que traduzca cada índice de bits a un índice de bytes, para optimizar la velocidad.
Lundin
2
En cuanto a big / little endian, big endian asignará enteros y datos sin procesar (por ejemplo, cadenas) de la misma manera: de izquierda a derecha de msb a lsb en todo el mapa de bits. Mientras little endian mapeará enteros de izquierda a derecha como 7-0, 15-8, 23-18, 31-24, pero los datos sin procesar siguen siendo de izquierda a derecha msb a lsb. Entonces, cuán poco endian es mejor para su algoritmo particular está completamente más allá de mí, parece ser lo contrario.
Lundin
2
@R .. Una tabla puede ser útil si su plataforma no puede cambiar eficientemente, como los antiguos microchip mcu's, pero por supuesto, la división en la muestra es absolutamente ineficiente
jeb
12
Utilizar este:
intToggleNthBit(unsignedchar n,int num ){if(num &(1<< n))
num &=~(1<< n);else
num |=(1<< n);return num;}
set_bit Atomicallyset 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 andreturn its old value
test_and_clear_bit Clear a bit andreturn its old value
test_and_change_bit Change a bit andreturn its old value
test_bit Determine whether a bit isset
Nota: Aquí toda la operación ocurre en un solo paso. Por lo tanto, se garantiza que todos estos elementos serán atómicos incluso en computadoras SMP y son útiles para mantener la coherencia entre los procesadores.
Visual C 2010, y quizás muchos otros compiladores, tienen soporte directo para operaciones booleanas incorporadas. Un bit tiene dos valores posibles, al igual que un booleano, por lo que podemos usar booleanos en su lugar, incluso si ocupan más espacio que un solo bit en memoria en esta representación. Esto funciona, incluso el sizeof()operador funciona correctamente.
Por lo tanto, a su pregunta, IsGph[i] =1o IsGph[i] =0facilite la configuración y la limpieza de las carpetas.
Para buscar 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<sizeof(IsGph); i++){if(IsGph[i]){IsNotGph[i]=0;}else{IsNotGph[i]=1;}}
Tenga en cuenta que no hay nada "especial" en este código. Se trata un poco como un número entero, que técnicamente lo es. Un entero de 1 bit que puede contener 2 valores y solo 2 valores.
Una vez utilicé este enfoque para encontrar registros de préstamos duplicados, donde el número de préstamo era la clave ISAM, usando el número de préstamo de 6 dígitos como un índice en la matriz de bits. Salvajemente rápido, y después de 8 meses, demostró que el sistema mainframe del que estábamos obteniendo los datos estaba funcionando mal. La simplicidad de las matrices de bits hace que la confianza en su corrección sea muy alta, en comparación con un enfoque de búsqueda, por ejemplo.
std :: bitset es implementado como bits por la mayoría de los compiladores
galinette
@galinette, de acuerdo. El archivo de encabezado #include <bitset> es un buen recurso a este respecto. Además, el vector de clase especial <bool> para cuando necesita cambiar el tamaño del vector. El C ++ STL, 2ª edición, Nicolai M. Josuttis los cubre exhaustivamente en las páginas 650 y 281 respectivamente. C ++ 11 agrega algunas capacidades nuevas a std :: bitset, de especial interés para mí es una función hash en contenedores desordenados. ¡Gracias por el aviso! Voy a eliminar mi comentario de calambre cerebral. Bastante basura en la web. No quiero agregarle nada.
3
Esto utiliza al menos un byte completo de almacenamiento para cada uno bool. Quizás incluso 4 bytes para las configuraciones de C89 que se usan intpara implementarbool
MM
@MattMcNabb, tienes razón. En C ++, el tamaño del tipo int necesario para implementar un booleano no está especificado por el estándar. Me di cuenta de que esta respuesta fue un error hace algún tiempo, pero decidí dejarla aquí, ya que la gente aparentemente la encuentra útil. Para aquellos que quieran usar bits, el comentario de Galinette es de gran ayuda, al igual que mi biblioteca de bits aquí ... stackoverflow.com/a/16534995/1899861
2
@RocketRoy: Probablemente valga la pena cambiar la oración que dice que este es un ejemplo de "operaciones de bit", entonces.
Ben Voigt
6
Utilice uno de los operadores como se define aquí .
Para establecer un bit, se usa int x = x | 0x?;donde ?está la posición del bit en forma binaria.
@ Xeverous sí, depende de la intención de las personas que llaman
Sazzad Hissain Khan
5
Supongamos que algunas cosas primero num = 55 Integer realizar operaciones bit a bit (set, get, clear, toggle). n = 4Posición de bit basada en 0 para realizar operaciones bit a bit.
¿Cómo conseguir un poco?
Para obtener el nthbit de desplazamiento a la derecha num num, ntiempos. Luego realice bit a bit Y &con 1.
Realice un complemento bit a bit con el resultado anterior. De modo que el enésimo bit se desarma y el resto del bit se pone, es decir ~ (1 << n).
Finalmente, realice la &operación AND a nivel de bit con el resultado anterior y num. Los tres pasos anteriores juntos se pueden escribir como num & (~ (1 << n));
num &=(~(1<< n));// Equivalent to; num = num & (~(1 << n));
Para alternar un poco, usamos el ^operador XOR bit a bit . El operador XOR bit a bit evalúa a 1 si el bit correspondiente de ambos operandos es diferente, de lo contrario se evalúa a 0.
Lo que significa alternar un poco, necesitamos realizar la operación XOR con el bit que desea alternar y 1.
num ^=(1<< n);// Equivalent to; num = num ^ (1 << n);
¿Cómo funciona?
Si el bit para alternar es 0, entonces 0 ^ 1 => 1.
Si el bit para alternar es 1, entonces 1 ^ 1 => 0.
Gracias por la explicación detallada. Aquí está el enlace para el problema de la práctica de la magia BIT enlace
Chandra Shekhar
4
¿Cómo establece, limpia y alterna un solo bit?
Para abordar un error de codificación común al intentar formar la máscara: 1no siempre es lo suficientemente ancho
¿Qué problemas ocurren cuando numberes un tipo más amplio que 1? xpuede ser demasiado bueno para el cambio que 1 << xconduce a un comportamiento indefinido (UB). Incluso si xno es demasiado bueno, ~puede que no voltee suficientes bits más significativos.
// assume 32 bit int/unsignedunsignedlonglong 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
Para asegurar 1 es lo suficientemente ancho:
El código podría usarse 1ullo pedantemente (uintmax_t)1y permitir que el compilador se optimice.
number |=(1ull<< x);
number |=((uintmax_t)1<< x);
O emitir, lo que hace que los problemas de codificación / revisión / mantenimiento mantengan el reparto correcto y actualizado.
number |=(type_of_number)1<< x;
O promueva suavemente 1forzando una operación matemática que sea tan ancha como el tipo de number.
number |=(number*0+1)<< x;
Al igual que con la mayoría de las manipulaciones de bits, mejor trabajar con sin signo tipos en lugar de firmados los
¡Una mirada interesante sobre una vieja pregunta! Ni apropiado number |= (type_of_number)1 << x;ni number |= (number*0 + 1) << x;apropiado para establecer el bit de signo de un tipo con signo ... De hecho, tampoco lo es number |= (1ull << x);. ¿Hay alguna forma portátil de hacerlo por posición?
chqrlie
1
@chqrlie IMO, la mejor manera de evitar establecer el bit de signo y arriesgar UB o IDB con cambios es usar tipos sin signo . El código firmado de cambio altamente portátil es demasiado complicado para ser aceptable.
chux - Restablecer Monica
3
Una versión con plantilla de C ++ 11 (poner en un encabezado):
Este código está roto (Además, ¿por qué tiene ;después de sus definiciones de función?)
Melpomene
@melpomene El código no está roto, lo probé. ¿Quiere decir que no se compilará o que el resultado es incorrecto? Sobre el extra ';' No recuerdo, esos pueden eliminarse de hecho.
Joakim L. Christiansen
(variable & bits == bits)?
melpomene
Gracias por notarlo, se suponía que era((variable & bits) == bits)
Joakim L. Christiansen
uso std::bitseten c ++ 11
pqnet
0
Este programa se basa en la solución anterior de @ Jeremy. Si alguien desea jugar rápidamente.
Respuestas:
Establecer un poco
Use el operador OR a nivel de bit (
|
) para establecer un bit.Eso establecerá el
n
th bit denumber
.n
debe ser cero, si desea establecer el1
bit st y así sucesivamenten-1
, si desea establecer eln
bit th.Use
1ULL
ifnumber
es más ancho queunsigned long
; la promoción de1UL << n
no ocurre hasta después de evaluar1UL << n
dónde es un comportamiento indefinido cambiar más de la anchura de along
. Lo mismo se aplica a todos los demás ejemplos.Despejando un poco
Use el operador AND a nivel de bit (
&
) para borrar un bit.Eso despejará la
n
parte denumber
. 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.Eso alternará la parte de
n
thnumber
.Comprobando un poco
No pediste esto, pero también podría agregarlo.
Para verificar un bit, desplace el número n hacia la derecha, luego bit a bit Y:
Eso pondrá el valor del
n
th bit denumber
en la variablebit
.Cambiar el n ésimo bit a x
Establecer el
n
bit th en cualquiera1
o0
se puede lograr con lo siguiente en una implementación C ++ del complemento a 2:El bit
n
se establecerá six
es1
y se borrará six
es así0
. Six
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 establecidos, a diferencia de un complemento de 1 o implementación de signo / magnitud C ++), use la negación sin signo.o
En general, es una buena idea usar tipos sin signo para la manipulación de bits portátil.
o
(number & ~(1UL << n))
borrará eln
bit th y(x << n)
establecerá eln
bit th enx
.También es generalmente una buena idea no copiar / pegar código en general, y muchas personas usan macros de preprocesador (como la respuesta de la wiki de la comunidad más abajo ) o algún tipo de encapsulación.
fuente
bit = (number >> x) & 1
1
es unint
literal, que está firmado. Entonces, todas las operaciones aquí operan con números firmados, que no están bien definidos por los estándares. Los estándares no garantizan el complemento de dos o el cambio aritmético, por lo que es mejor usarlo1U
.number = number & ~(1 << n) | (x << n);
cambiar el enésimo bit a x.Uso de la biblioteca estándar de C ++:
std::bitset<N>
.O el Boost versión:
boost::dynamic_bitset
.No hay necesidad de rodar el suyo:
La versión Boost permite un conjunto de bits de tamaño de tiempo de ejecución en comparación con un conjunto de bits de tamaño de compilación de biblioteca estándar .
fuente
La otra opción es usar campos de bits:
define un campo de 3 bits (en realidad, son tres campos de 1 bit). Las operaciones de bit ahora se vuelven un poco (jaja) más simples:
Para establecer o borrar un poco:
Para alternar un poco:
Comprobando un poco:
Esto solo funciona con campos de bits de tamaño fijo. De lo contrario, debe recurrir a las técnicas de cambio de bits descritas en publicaciones anteriores.
fuente
Uso macros definidas en un archivo de encabezado para manejar el conjunto de bits y borrar:
fuente
BITMASK_CHECK(x,y) ((x) & (y))
debe ser de lo((x) & (y)) == (y)
contrario, devuelve un resultado incorrecto en la máscara multibit (ej.5
vs.3
) / * Hola a todos los sepultureros1
debería ser(uintmax_t)1
o similar en caso de que alguien intente usar estas macros en unlong
tipo o más grandeBITMASK_CHECK_ALL(x,y)
se puede implementar como!~((~(y))|(x))
!(~(x) & (y))
A veces vale la pena usar un
enum
para nombrar los bits:Luego use los nombres más adelante. Es decir, escribir
para establecer, borrar y probar. De esta manera, oculta los números mágicos del resto de su código.
Aparte de eso, respaldo la solución de Jeremy.
fuente
clearbits()
función en lugar de&= ~
. ¿Por qué estás usando una enumeración para esto? Pensé que eran para crear un montón de variables únicas con un valor arbitrario oculto, pero estás asignando un valor definido a cada una. Entonces, ¿cuál es el beneficio en comparación con solo definirlos como variables?enum
s para conjuntos de constantes relacionadas se remonta mucho en la programación de c. Sospecho que con los compiladores modernos, la única ventaja sobre,const short
o lo que sea, es que están agrupados explícitamente. Y cuando los quiere para algo más que máscaras de bits, obtiene la numeración automática. En c ++, por supuesto, también forman tipos distintos que le brindan un poco más de comprobación de errores estáticos.enum ThingFlags
sirveThingError|ThingFlag1
, por ejemplo?int
. Esto puede causar todo tipo de errores sutiles debido a la promoción de números enteros implícitos u operaciones bit a bit en tipos firmados.thingstate = ThingFlag1 >> 1
invocará, por ejemplo, un comportamiento definido por la implementación.thingstate = (ThingFlag1 >> x) << y
puede invocar un comportamiento indefinido. Y así. Para estar seguro, utilice siempre un tipo sin signo.enum My16Bits: unsigned short { ... };
De los bitops.h de snip-c.zip:
OK, analicemos las cosas ...
La expresión común con la que parece estar teniendo problemas en todo esto es "(1L << (posn))". Todo lo que hace es crear una máscara con un solo bit y que funcionará con cualquier tipo de entero. El argumento "posn" especifica la posición donde desea el bit. Si posn == 0, entonces esta expresión se evaluará para:
Si posn == 8, se evaluará para:
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 necesitamos establecer un solo 0 bit en un campo de 1. Esto se logra utilizando el complemento de 1 de la misma expresión que denota el operador 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 (^). Como la máscara es de 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 macros ocurre en el preprocesador, por lo que el código generado reflejará el hecho de que el compilador considera que los valores son constantes, es decir, es tan eficiente usar las macros generalizadas como "reinventar la rueda" cada vez que necesite hacer manipulación de bits.
Poco convencido? Aquí hay un código de prueba: utilicé Watcom C con optimización completa y sin usar _cdecl, por lo que el desmontaje resultante sería lo más limpio posible:
---- [TEST.C] ----------------------------------------- -----------------------
---- [TEST.OUT (desmontado)] -------------------------------------- ---------
---- [finis] ------------------------------------------- ----------------------
fuente
arg
es asílong long
.1L
necesita ser el tipo más amplio posible, entonces(uintmax_t)1
. (Puede salirse con la suya1ull
)Use los operadores bit a bit:
&
|
Para configurar el último bit en
000b
:Para comprobar el último bit en
foo
:Para borrar el último bit en
foo
:Solía
XXXb
por claridad. Probablemente trabajará con representación HEX, dependiendo de la estructura de datos en la que está empacando bits.fuente
foo = foo ^ MY_MASK
foo = foo & ~MY_MASK
Para el principiante, me gustaría explicar un poco más con un ejemplo:
Ejemplo:
El
&
operador se utiliza comprobar el bit:Alternar o voltear:
|
operador: establece el bitfuente
Aquí está mi macro aritmética de bits favorita, que funciona para cualquier tipo de matriz entera sin signo de
unsigned char
hastasize_t
(que es el tipo más grande con el que debería ser eficiente trabajar):Para establecer un poco:
Para despejar un poco:
Para alternar un poco:
Para probar un poco:
etc.
fuente
BITOP(array, bit++, |=);
en bucle probablemente no hará lo que la persona que llama desea.BITCELL(a,b) |= BITMASK(a,b);
(ambos tomana
como argumento para determinar el tamaño, pero este último nunca se evaluaríaa
ya que aparece solo ensizeof
).(size_t)
elenco parece ser no sólo para asegurar cierta matemáticas sin firmar con%
. Podría(unsigned)
allí.(size_t)(b)/(8*sizeof *(a))
innecesariamente podría reducirseb
antes de la división. Solo un problema con matrices de bits muy grandes. Sigue siendo una macro interesante.Como esto está etiquetado como "incrustado", supondré que está utilizando un microcontrolador. Todas las sugerencias anteriores son válidas y funcionan (lectura-modificación-escritura, uniones, estructuras, etc.).
Sin embargo, durante una serie de depuración basada en el osciloscopio, me sorprendió descubrir que estos métodos tienen una sobrecarga considerable en los ciclos de la CPU en comparación con escribir un valor directamente en los registros PORTnSET / PORTnCLEAR del micro, lo que hace una diferencia real cuando hay bucles estrechos / altos -frecuencia ISR pasadores de alternancia.
Para aquellos que no están familiarizados: en mi ejemplo, el micro tiene un registro general de estado de pin 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 un '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 "deje el pin en paz". entonces, terminas con dos direcciones de puerto dependiendo de si estás configurando o borrando el bit (no siempre es conveniente) pero una reacción mucho más rápida y un código ensamblado más pequeño.
fuente
volatile
y, por lo tanto, el compilador no puede realizar ninguna optimización en el código que involucra dichos registros. Por lo tanto, es una buena práctica desensamblar dicho código y ver cómo resultó a nivel de ensamblador.El enfoque de campo de bits tiene otras ventajas en el ámbito integrado. Puede definir una estructura que se asigne directamente a los bits en un registro de hardware particular.
Debe tener en cuenta el orden de empaquetado de bits: creo que es MSB primero, pero esto puede depender de la implementación. Además, verifique cómo los manejadores del compilador cruzan los límites de bytes.
Luego puede leer, escribir, probar los valores individuales como antes.
fuente
Marque un bit en una ubicación arbitraria en una variable de tipo arbitrario:
Uso de la muestra:
Notas: Esto está diseñado para ser rápido (dada su flexibilidad) y no ramificado. Da como resultado un código de máquina SPARC eficiente cuando se compila Sun Studio 8; También lo probé usando MSVC ++ 2008 en amd64. Es posible hacer macros similares para configurar y borrar bits. La diferencia clave de esta solución en comparación con muchas otras aquí es que funciona para cualquier ubicación en prácticamente cualquier tipo de variable.
fuente
Más general, para mapas de bits de tamaño arbitrario:
fuente
CHAR_BIT
ya está definido porlimits.h
, no necesita poner el suyoBITS
(y de hecho empeora su código al hacerlo)Este programa es para cambiar cualquier bit de datos de 0 a 1 o 1 a 0:
fuente
Si está haciendo muchos giros, es posible que desee usar máscaras que harán que todo sea más rápido. Las siguientes funciones son muy rápidas y siguen siendo flexibles (permiten girar bits en mapas de bits de cualquier tamaño).
Tenga en cuenta que para establecer el bit 'n' en un entero de 16 bits, haga lo siguiente:
Depende de usted asegurarse de que el número de bits esté dentro del rango del mapa de bits que pasa. Tenga en cuenta que para los pequeños procesadores endian que bytes, palabras, dwords, qwords, etc., se asignan correctamente entre sí en la memoria (razón principal de que los pequeños procesadores endian son "mejores" que los procesadores big endian, ah, siento que se acerca una guerra de llamas en...).
fuente
Utilizar este:
fuente
Ampliando la
bitset
respuesta:fuente
Si desea realizar todas estas operaciones con la programació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
Nota: Aquí toda la operación ocurre en un solo paso. Por lo tanto, se garantiza que todos estos elementos serán atómicos incluso en computadoras SMP y son útiles para mantener la coherencia entre los procesadores.
fuente
Visual C 2010, y quizás muchos otros compiladores, tienen soporte directo para operaciones booleanas incorporadas. Un bit tiene dos valores posibles, al igual que un booleano, por lo que podemos usar booleanos en su lugar, incluso si ocupan más espacio que un solo bit en memoria en esta representación. Esto funciona, incluso el
sizeof()
operador funciona correctamente.Por lo tanto, a su pregunta,
IsGph[i] =1
oIsGph[i] =0
facilite la configuración y la limpieza de las carpetas.Para buscar caracteres no imprimibles:
Tenga en cuenta que no hay nada "especial" en este código. Se trata un poco como un número entero, que técnicamente lo es. Un entero de 1 bit que puede contener 2 valores y solo 2 valores.
Una vez utilicé este enfoque para encontrar registros de préstamos duplicados, donde el número de préstamo era la clave ISAM, usando el número de préstamo de 6 dígitos como un índice en la matriz de bits. Salvajemente rápido, y después de 8 meses, demostró que el sistema mainframe del que estábamos obteniendo los datos estaba funcionando mal. La simplicidad de las matrices de bits hace que la confianza en su corrección sea muy alta, en comparación con un enfoque de búsqueda, por ejemplo.
fuente
bool
. Quizás incluso 4 bytes para las configuraciones de C89 que se usanint
para implementarbool
Utilice uno de los operadores como se define aquí .
Para establecer un bit, se usa
int x = x | 0x?;
donde?
está la posición del bit en forma binaria.fuente
0x
es el prefijo para un literal en hexadecimal, no binario.Aquí hay algunas macros que uso:
fuente
Variable utilizada
valor -
Posición de datos - posición del bit que estamos interesados en establecer, borrar o alternar.
Establecer un poco:
Claro un poco:
Alternar un poco:
fuente
fuente
check_nth_bit
puede serbool
.¿Cómo conseguir un poco?
nth
bit de desplazamiento a la derecha numnum
,n
tiempos. Luego realice bit a bit Y&
con 1.¿Cómo funciona?
¿Cómo configurar un poco?
n
veces. Luego realice la|
operación OR a nivel de bit connum
.¿Cómo funciona?
¿Cómo despejar un poco?
n
ej1 << n
.~ (1 << n)
.&
operación AND a nivel de bit con el resultado anterior ynum
. Los tres pasos anteriores juntos se pueden escribir comonum & (~ (1 << n))
;¿Cómo funciona?
¿Cómo alternar un poco?
Para alternar un poco, usamos el
^
operador XOR bit a bit . El operador XOR bit a bit evalúa a 1 si el bit correspondiente de ambos operandos es diferente, de lo contrario se evalúa a 0.Lo que significa alternar un poco, necesitamos realizar la operación XOR con el bit que desea alternar y 1.
¿Cómo funciona?
0 ^ 1 => 1
.1 ^ 1 => 0
.Lectura recomendada: ejercicios de operador bit a bit
fuente
Para abordar un error de codificación común al intentar formar la máscara:
1
no siempre es lo suficientemente ancho¿Qué problemas ocurren cuando
number
es un tipo más amplio que1
?x
puede ser demasiado bueno para el cambio que1 << x
conduce a un comportamiento indefinido (UB). Incluso six
no es demasiado bueno,~
puede que no voltee suficientes bits más significativos.Para asegurar 1 es lo suficientemente ancho:
El código podría usarse
1ull
o pedantemente(uintmax_t)1
y permitir que el compilador se optimice.O emitir, lo que hace que los problemas de codificación / revisión / mantenimiento mantengan el reparto correcto y actualizado.
O promueva suavemente
1
forzando una operación matemática que sea tan ancha como el tipo denumber
.Al igual que con la mayoría de las manipulaciones de bits, mejor trabajar con sin signo tipos en lugar de firmados los
fuente
number |= (type_of_number)1 << x;
ninumber |= (number*0 + 1) << x;
apropiado para establecer el bit de signo de un tipo con signo ... De hecho, tampoco lo esnumber |= (1ull << x);
. ¿Hay alguna forma portátil de hacerlo por posición?Una versión con plantilla de C ++ 11 (poner en un encabezado):
fuente
;
después de sus definiciones de función?)(variable & bits == bits)
?((variable & bits) == bits)
std::bitset
en c ++ 11Este programa se basa en la solución anterior de @ Jeremy. Si alguien desea jugar rápidamente.
fuente
Pruebe una de estas funciones en el lenguaje C para cambiar n bit:
O
O
fuente
value << n
puede causar un comportamiento indefinido