¿Cómo obtengo datos bit a bit de un valor entero en C?


99

Quiero extraer bits de un número decimal.

Por ejemplo, 7 es 0111 binario y quiero obtener 0 1 1 1 todos los bits almacenados en bool. ¿Como lo puedo hacer?

Bien, un bucle no es una buena opción, ¿puedo hacer algo más para esto?

Respuestas:


153

Si quieres el k-ésimo bit de n, hazlo

(n & ( 1 << k )) >> k

Aquí creamos una máscara, aplicamos la máscara an, y luego desplazamos a la derecha el valor enmascarado para obtener solo el bit que queremos. Podríamos escribirlo más completamente como:

    int mask =  1 << k;
    int masked_n = n & mask;
    int thebit = masked_n >> k;

Puede leer más sobre el enmascaramiento de bits aquí .

Aquí hay un programa:

#include <stdio.h>
#include <stdlib.h>

int *get_bits(int n, int bitswanted){
  int *bits = malloc(sizeof(int) * bitswanted);

  int k;
  for(k=0; k<bitswanted; k++){
    int mask =  1 << k;
    int masked_n = n & mask;
    int thebit = masked_n >> k;
    bits[k] = thebit;
  }

  return bits;
}

int main(){
  int n=7;

  int  bitswanted = 5;

  int *bits = get_bits(n, bitswanted);

  printf("%d = ", n);

  int i;
  for(i=bitswanted-1; i>=0;i--){
    printf("%d ", bits[i]);
  }

  printf("\n");
}

70
(n >> k) & 1es igualmente válido y no requiere calcular la máscara ya que la máscara es constante debido al cambio antes de enmascarar en lugar de al revés.
Joe

@Joe, ¿puedes explicar eso, quizás en una respuesta, por favor?
Dan Rosenstark

1
@Yar extendió un poco mi comentario y agregó una nueva respuesta según lo solicitado
Joe

Cuando se utilizan bits conocidos para la información (es decir, para protocolos de red, como Websockets), la conversión de los datos en un structarchivo también puede ser útil, ya que obtiene todos los datos necesarios con una sola operación.
Myst

@forefinger, ¿puede publicar una salida de ejemplo del código?
Ashish Ahuja

83

Como se solicitó, decidí extender mi comentario sobre la respuesta de índice a una respuesta completa. Aunque su respuesta es correcta, es innecesariamente compleja. Además, todas las respuestas actuales utilizan ints con signo para representar los valores. Esto es peligroso, ya que el desplazamiento a la derecha de los valores negativos está definido por la implementación (es decir, no es portátil) y el desplazamiento a la izquierda puede conducir a un comportamiento indefinido (consulte esta pregunta ).

Al desplazar a la derecha el bit deseado a la posición de bit menos significativa, se puede realizar el enmascaramiento 1. No es necesario calcular un nuevo valor de máscara para cada bit.

(n >> k) & 1

Como programa completo, calcula (y posteriormente imprime) una matriz de valores de un solo bit:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
    unsigned
        input = 0b0111u,
        n_bits = 4u,
        *bits = (unsigned*)malloc(sizeof(unsigned) * n_bits),
        bit = 0;

    for(bit = 0; bit < n_bits; ++bit)
        bits[bit] = (input >> bit) & 1;

    for(bit = n_bits; bit--;)
        printf("%u", bits[bit]);
    printf("\n");

    free(bits);
}

Suponiendo que desea calcular todos los bits como en este caso, y no uno específico, el bucle se puede cambiar más a

for(bit = 0; bit < n_bits; ++bit, input >>= 1)
    bits[bit] = input & 1;

Esto se modifica inputen su lugar y por lo tanto permite el uso de un desplazamiento de un solo bit de ancho constante, que puede ser más eficiente en algunas arquitecturas.


5

Aquí hay una forma de hacerlo, hay muchas otras:

bool b[4];
int v = 7;  // number to dissect

for (int j = 0;  j < 4;  ++j)
   b [j] =  0 != (v & (1 << j));

Es difícil entender por qué no se desea el uso de un bucle, pero es bastante fácil desenrollar el bucle:

bool b[4];
int v = 7;  // number to dissect

b [0] =  0 != (v & (1 << 0));
b [1] =  0 != (v & (1 << 1));
b [2] =  0 != (v & (1 << 2));
b [3] =  0 != (v & (1 << 3));

O evaluar expresiones constantes en las últimas cuatro declaraciones:

b [0] =  0 != (v & 1);
b [1] =  0 != (v & 2);
b [2] =  0 != (v & 4);
b [3] =  0 != (v & 8);

3

He aquí una forma muy sencilla de hacerlo;

int main()
{
    int s=7,l=1;
    vector <bool> v;
    v.clear();
    while (l <= 4)
    {
        v.push_back(s%2);
        s /= 2;
        l++;
    }
    for (l=(v.size()-1); l >= 0; l--)
    {
        cout<<v[l]<<" ";
    }
    return 0;
}

1

@prateek gracias por tu ayuda. Reescribí la función con comentarios para usarla en un programa. Aumente 8 para obtener más bits (hasta 32 para un número entero).

std::vector <bool> bits_from_int (int integer)    // discern which bits of PLC codes are true
{
    std::vector <bool> bool_bits;

    // continously divide the integer by 2, if there is no remainder, the bit is 1, else it's 0
    for (int i = 0; i < 8; i++)
    {
        bool_bits.push_back (integer%2);    // remainder of dividing by 2
        integer /= 2;    // integer equals itself divided by 2
    }

    return bool_bits;
}

1

Si no quiere ningún bucle, tendrá que escribirlo:

#include <stdio.h>
#include <stdbool.h>

int main(void)
{
    int num = 7;

    #if 0
        bool arr[4] = { (num&1) ?true: false, (num&2) ?true: false, (num&4) ?true: false, (num&8) ?true: false };
    #else
        #define BTB(v,i) ((v) & (1u << (i))) ? true : false
        bool arr[4] = { BTB(num,0), BTB(num,1), BTB(num,2), BTB(num,3)};
        #undef BTB
    #endif

    printf("%d %d %d %d\n", arr[3], arr[2], arr[1], arr[0]);

    return 0;
}

Como se demuestra aquí, esto también funciona en un inicializador.


0
#include <stdio.h>

int main(void)
{
    int number = 7; /* signed */
    int vbool[8 * sizeof(int)];
    int i;
        for (i = 0; i < 8 * sizeof(int); i++)
        {
            vbool[i] = number<<i < 0;   
            printf("%d", vbool[i]);
        }
    return 0;
}

0

Utilizando std::bitset

int value = 123;
std::bitset<sizeof(int)> bits(value);
std::cout <<bits.to_string();

Es un método útil, pero hay algo incorrecto en el ejemplo. bitset <n>, n es el número de bits, por lo que el uso de sizeof (int) es incorrecto.
Jerry Chou
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.