C / C ++ comprueba si se establece un bit, es decir, variable int


100
int temp = 0x5E; // in binary 0b1011110.

¿Existe alguna manera de verificar si el bit 3 en temp es 1 o 0 sin desplazamiento de bits y enmascaramiento?

Solo quiero saber si hay alguna función incorporada para esto, o me veo obligado a escribir una yo mismo.

Respuestas:


157

En C, si desea ocultar la manipulación de bits, puede escribir una macro:

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

y utilícelo de esta manera para verificar el n- ésimo bit desde el extremo derecho:

CHECK_BIT(temp, n - 1)

En C ++, puede usar std :: bitset .


3
En caso de que necesite un valor de verdad simple, debería ser !! ((var) & (1 << (pos))).
Eduard - Gabriel Munteanu

10
@Eduard: en C, todo != 0es cierto, entonces ¿para qué molestarse? 1es exactamente tan cierto como 0.1415!
Christoph

1
Y en caso de que esté usando C ++, podría (debería) escribir una plantilla en lugar de una macro. :)
jalf

2
En C esto está bien. Pero este tipo de macros en C ++. Eso es horrible y tan abierto al abuso. Use std :: bitset
Martin York

5
Ugh, std::bitset¿en serio? Claro, en lugar de hacer un poco de trabajo (y potencialmente algunas plantillas realmente agradables) para verificar un solo bit, use un contenedor inflado que almacene (en mi implementación) cada 'bit' en un lugar que de otro modo no se usaría unsigned long. ¡Qué desperdicio de espacio!
underscore_d

86

Compruebe si el bit N (a partir de 0) está establecido:

temp & (1 << N)

No hay una función incorporada para esto.


16
+1 por mencionar que está comenzando desde 0 ya que sospecho que el OP estaba pensando en 1 y la respuesta aceptada lo meterá en problemas. :)
Jim Buck

Hm. ¿Por qué empieza desde 0? ¿Qué obtenemos cuando 1 << 0? Lo siento, confundido.
Danijel

6
Ok lo tengo. Partimos de la posición 0, que es 1<<0, que es 1 sin ningún cambio (turno 0), que es1<<0 == 1
Danijel

27

Solo usaría un std :: bitset si es C ++. Sencillo. Sencillo. No hay posibilidad de errores estúpidos.

typedef std::bitset<sizeof(int)> IntBits;
bool is_set = IntBits(value).test(position);

o que tal esta tontería

template<unsigned int Exp>
struct pow_2 {
    static const unsigned int value = 2 * pow_2<Exp-1>::value;
};

template<>
struct pow_2<0> {
    static const unsigned int value = 1;
};

template<unsigned int Pos>
bool is_bit_set(unsigned int value)
{
    return (value & pow_2<Pos>::value) != 0;
} 

bool result = is_bit_set<2>(value);

4
@ user21714 Supongo que quiso decir std :: bitset <8 * sizeof (int)>
iNFINITEi

o std :: numeric_limits <int> :: dígitos
Léo Lam

@iNFINITEi std::bitset<CHAR_BIT * sizeof(int)>para ser aún más correcto
Xeverous

13

Sí, sé que no "tengo" que hacerlo de esta manera. Pero suelo escribir:

    /* Return type (8/16/32/64 int size) is specified by argument size. */
template<class TYPE> inline TYPE BIT(const TYPE & x)
{ return TYPE(1) << x; }

template<class TYPE> inline bool IsBitSet(const TYPE & x, const TYPE & y)
{ return 0 != (x & y); }

P.ej:

IsBitSet( foo, BIT(3) | BIT(6) );  // Checks if Bit 3 OR 6 is set.

Entre otras cosas, este enfoque:

  • Acepta números enteros de 8/16/32/64 bits.
  • Detecta llamadas IsBitSet (int32, int64) sin mi conocimiento y consentimiento.
  • Plantilla en línea, por lo que no hay función que llame a la sobrecarga.
  • const y referencias, por lo que no es necesario duplicar / copiar nada . Y tenemos la garantía de que el compilador detectará cualquier error tipográfico que intente cambiar los argumentos.
  • 0! = Hace que el código sea más claro y obvio. El punto principal para escribir código es siempre comunicarse de manera clara y eficiente con otros programadores, incluidos los de menor habilidad.
  • Si bien no es aplicable a este caso en particular ... En general, las funciones con plantilla evitan el problema de evaluar argumentos varias veces. Un problema conocido con algunas macros #define.
    Por ejemplo: #define ABS (X) (((X) <0)? - (X): (X))
          ABS (i ++);

13

Lo que hace la respuesta seleccionada es realmente incorrecto. La siguiente función devolverá la posición del bit o 0 dependiendo de si el bit está realmente habilitado. Esto no es lo que pedía el cartel.

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

Esto es lo que buscaba originalmente el póster. La siguiente función devolverá un 1 o un 0 si el bit está habilitado y no la posición.

#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)

1
Pasó algún tiempo hasta que entendí lo que quieres decir. Más exacto: la primera función devuelve 2 a la potencia de la posición del bit si el bit está establecido, 0 en caso contrario.
lukasl1991

1
Este es el problema exacto que acabo de encontrar al usarlo como Es bool has_feature = CHECK_BIT(register, 25);bueno saber que podría hacerlo sin la doble negación.
Jimmio92

11

Según esta descripción de los campos de bits , existe un método para definir y acceder a los campos directamente. El ejemplo de esta entrada es:

struct preferences {
    unsigned int likes_ice_cream : 1;
    unsigned int plays_golf : 1;
    unsigned int watches_tv : 1;
    unsigned int reads_books : 1;
}; 

struct preferences fred;

fred.likes_ice_cream = 1;
fred.plays_golf = 1;
fred.watches_tv = 1;
fred.reads_books = 0;

if (fred.likes_ice_cream == 1)
    /* ... */

Además, hay una advertencia allí:

Sin embargo, los miembros de bit en estructuras tienen inconvenientes prácticos. Primero, el orden de los bits en la memoria depende de la arquitectura y las reglas de relleno de la memoria varían de un compilador a otro. Además, muchos compiladores populares generan código ineficiente para leer y escribir miembros de bits, y existen problemas de seguridad de subprocesos potencialmente graves relacionados con los campos de bits (especialmente en sistemas multiprocesador) debido al hecho de que la mayoría de las máquinas no pueden manipular conjuntos arbitrarios de bits en la memoria. pero debe cargar y almacenar palabras completas.



5

Utilice std :: bitset

#include <bitset>
#include <iostream>

int main()
{
    int temp = 0x5E;
    std::bitset<sizeof(int)*CHAR_BITS>   bits(temp);

    // 0 -> bit 1
    // 2 -> bit 3
    std::cout << bits[2] << std::endl;
}

1
Un par de cosas que vale la pena mencionar aquí: los bits [3] le darán el cuarto bit, contando desde el LSB al MSB. En pocas palabras, le dará el 4 el bit contando de derecha a izquierda. Además, sizeof (int) da el número de caracteres en un int, por lo que debería ser std :: bitset <sizeof (int) * CHAR_BITS> bits (temp) y bits [sizeof (int) * CHAR_BITS - 3] para probar el tercer bit contando de MSB a LSB, que es probablemente la intención.
chris plástico

2
Sí, pero creo que el interrogador (y las personas que vienen de las búsquedas de Google) podrían no tener esa habilidad y tu respuesta podría engañarlos.
plástico chris

Esta respuesta es terrible. Debería eliminarse.
Adam Burry

¿No es tempnecesario reflejar el valor para convertirlo en "big-endian"?
jww

4

Existe, a saber, la instrucción intrínseca _bittest .


3
El enlace indica "Específico de Microsoft". Úselo solo si no necesita que su código sea portátil.
mouviciel

El enlace indica "Específico de Microsoft", pero es un intrínseco tomado del compilador Intel C ++, y da como resultado una instrucción BT, por lo que también puede hacerlo con ensamblador en línea. Por supuesto, eso no lo hace más portátil.
Dave Van den Eynde

1
También es específico de la arquitectura x86. Así que no, definitivamente no es portátil.
jalf

Estoy seguro de que otras arquitecturas tienen opciones similares.
Dave Van den Eynde

El punto mismo de los intrínsecos es que aprovechan el hardware si existe, y usan un reemplazo de software si el hardware no lo maneja.
Eclipse

4

Yo uso esto:

#define CHECK_BIT(var,pos) ( (((var) & (pos)) > 0 ) ? (1) : (0) )

donde "pos" se define como 2 ^ n (ig 1,2,4,8,16,32 ...)

Devuelve: 1 si es verdadero 0 si es falso


2
Creo que esta es la única respuesta correcta tanto para C como para C ++. Es el único que respeta el requisito "... sin cambio de bits ni enmascaramiento" . Probablemente debería indicar explícitamente el uso 4 = 2^(3-1)para la posición de bit 3, ya que era parte de la pregunta.
jww

3

Estaba tratando de leer un entero de 32 bits que definía las banderas para un objeto en archivos PDF y esto no me funcionaba

lo que solucionó fue cambiar la definición:

#define CHECK_BIT(var,pos) ((var & (1 << pos)) == (1 << pos))

el operando y devuelve un número entero con las banderas que ambos tienen en 1, y no se estaba convirtiendo correctamente en booleano, esto funcionó


!= 0haría lo mismo. No sé en qué pueden diferir las instrucciones de la máquina generada.
Adam Burry

2

Podría "simular" cambios y enmascaramiento: if ((0x5e / (2 * 2 * 2))% 2) ...


Podríamos ordenar una lista barajándola aleatoriamente y probando para ver si ahora está "ordenada". Por ejemplo: while (/ * NOT * /! IsSorted ()) {RandomlyShuffle (); } Pero nosotros no ...
Mr.Ree

Esta solución es extremadamente derrochadora de recursos y poco intuitiva. divs, muls y mods son las tres funciones más caras. según las pruebas de comparación, los ands y los turnos se encuentran entre los más baratos: algunos de los pocos que puede hacer en menos de 5 ciclos.
jheriko

Eso podría ser (y no lo es, porque los procesadores modernos detestan los bits y los saltos). El OP pidió originalmente explícitamente una solución "sin cambio de bits ni enmascaramiento". Así que continúe y dé más puntos negativos por una respuesta coincidente pero lenta. No eliminaré la publicación solo porque el OP cambió de opinión.
Leonidas

Parece complicado. No votemos en contra de esta respuesta. A veces es bueno explorar otras vistas.
Viet

2

Para la solución específica x86 de bajo nivel, use el código de operación x86 TEST .

Sin embargo, su compilador debería convertir _bittest en esto ...


Preferiría BT sobre TEST ya que BT se adapta mejor a la tarea.
u_Ltd.

1

¿Por qué no usar algo tan simple como esto?

uint8_t status = 255;
cout << "binary: ";

for (int i=((sizeof(status)*8)-1); i>-1; i--)
{
  if ((status & (1 << i)))
  {
    cout << "1";
  } 
  else
  {
    cout << "0";
  }
}

SALIDA: binaria: 11111111


si otra cosa se puede hacer fácilmente con un ternario: std::cout << (((status & (1 << i)) ? '1' : '0');. Debe usar la CHAR_BITconstante de en <climits>lugar de codificar 8 bits, aunque en este caso sabe que el resultado será 8 de todos modos, ya que está usando unuint8_t
Ryan Haining

0

si solo quieres una forma realmente codificada:

 #define IS_BIT3_SET(var) ( ((var) & 0x04) == 0x04 )

tenga en cuenta que esto depende de hw y asume este orden de bits 7654 3210 y var es de 8 bits.

#include "stdafx.h"
#define IS_BIT3_SET(var) ( ((var) & 0x04) == 0x04 )
int _tmain(int argc, _TCHAR* argv[])
{
    int temp =0x5E;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0x00;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0x04;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0xfb;
    printf(" %d \n", IS_BIT3_SET(temp));
    scanf("waitng %d",&temp);

    return 0;
}

Resultados en:

1 0 1 0


1
La operación & se realiza en valores que no están en la representación interna.
Remo.D

Hola Remo.D - ¿No estás seguro de entender tu comentario? He incluido un código 'c' que funciona bien.
Simon

Su punto es que no depende del hardware: IS_BIT3_SET siempre probará el cuarto bit menos significativo
Eclipse

0

Si bien es bastante tarde para responder ahora, hay una manera simple de encontrar si el bit N está establecido o no, simplemente usando los operadores matemáticos POWER y MODULUS.

Digamos que queremos saber si 'temp' tiene el N-ésimo bit establecido o no. La siguiente expresión booleana dará verdadero si el bit está establecido, 0 en caso contrario.

  • (temp MÓDULO 2 ^ N + 1> = 2 ^ N)

Considere el siguiente ejemplo:

  • int temp = 0x5E; // en binario 0b1011110 // BIT 0 es LSB

Si quiero saber si el tercer bit está configurado o no, obtengo

  • (94 MÓDULO 16) = 14> 2 ^ 3

Entonces expresión devuelve verdadero, lo que indica que el tercer bit está establecido.


0

Un enfoque será verificar dentro de la siguiente condición:

if ( (mask >> bit ) & 1)

Un programa de explicación será:

#include <stdio.h>

unsigned int bitCheck(unsigned int mask, int pin);

int main(void){
   unsigned int mask = 6;  // 6 = 0110
   int pin0 = 0;
   int pin1 = 1;
   int pin2 = 2;
   int pin3 = 3;
   unsigned int bit0= bitCheck( mask, pin0);
   unsigned int bit1= bitCheck( mask, pin1);
   unsigned int bit2= bitCheck( mask, pin2);
   unsigned int bit3= bitCheck( mask, pin3);

   printf("Mask = %d ==>>  0110\n", mask);

   if ( bit0 == 1 ){
      printf("Pin %d is Set\n", pin0);
   }else{
      printf("Pin %d is not Set\n", pin0);
   }

    if ( bit1 == 1 ){
      printf("Pin %d is Set\n", pin1);
   }else{
      printf("Pin %d is not Set\n", pin1);
   }

   if ( bit2 == 1 ){
      printf("Pin %d is Set\n", pin2);
   }else{
      printf("Pin %d is not Set\n", pin2);
   }

   if ( bit3 == 1 ){
      printf("Pin %d is Set\n", pin3);
   }else{
      printf("Pin %d is not Set\n", pin3);
   }
}

unsigned int bitCheck(unsigned int mask, int bit){
   if ( (mask >> bit ) & 1){
      return 1;
   }else{
      return 0;
   }
}

Salida:

Mask = 6 ==>>  0110
Pin 0 is not Set
Pin 1 is Set
Pin 2 is Set
Pin 3 is not Set

0
#define CHECK_BIT(var,pos) ((var>>pos) & 1)

pos - Posición de bit comenzando desde 0.

devuelve 0 o 1.



-2

la forma más rápida parece ser una tabla de búsqueda de máscaras

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.