Como obtenho dados bit a bit de um valor inteiro em C?


99

Quero extrair bits de um número decimal.

Por exemplo, 7 é o binário 0111 e quero obter 0 1 1 1 todos os bits armazenados em bool. Como posso fazer isso?

OK, um loop não é uma boa opção, posso fazer outra coisa para isso?

Respostas:


154

Se você quiser o bit k-ésimo de n, faça

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

Aqui, criamos uma máscara, aplicamos a máscara a n e, em seguida, deslocamos para a direita o valor mascarado para obter apenas o bit que queremos. Poderíamos escrever mais detalhadamente como:

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

Você pode ler mais sobre mascaramento de bits aqui .

Aqui está um 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) & 1é igualmente válido e não requer o cálculo da máscara, pois a máscara é constante devido ao deslocamento antes da máscara em vez do contrário.
Joe

@Joe você pode explicar isso, talvez em uma resposta, por favor?
Dan Rosenstark

1
@Yar estendeu meu comentário um pouco e adicionou uma nova resposta conforme solicitado
Joe,

Ao usar bits conhecidos para informações (ou seja, para protocolos de rede, como Websockets), converter os dados em um também structpode ser útil, pois você obtém todos os dados necessários com uma única operação.
Myst

@forefinger, você pode postar um exemplo de saída do código.
Ashish Ahuja

83

Conforme solicitado, decidi estender meu comentário sobre a resposta do indicador a uma resposta completa. Embora sua resposta esteja correta, é desnecessariamente complexa. Além disso, todas as respostas atuais usam ints com sinais para representar os valores. Isso é perigoso, pois o deslocamento para a direita de valores negativos é definido pela implementação (ou seja, não é portátil) e o deslocamento para a esquerda pode levar a um comportamento indefinido (consulte esta pergunta ).

Deslocando para a direita o bit desejado para a posição de bit menos significativa, o mascaramento pode ser feito 1. Não há necessidade de calcular um novo valor de máscara para cada bit.

(n >> k) & 1

Como um programa completo, computando (e subsequentemente imprimindo) uma matriz de valores de bit único:

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

Supondo que você deseja calcular todos os bits como neste caso, e não um específico, o loop pode ser alterado para

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

Isso é modificado inputno local e, portanto, permite o uso de uma largura constante, deslocamento de um único bit, que pode ser mais eficiente em algumas arquiteturas.


5

Esta é uma maneira de fazer isso - existem muitas outras:

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

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

É difícil entender por que o uso de um loop não é desejado, mas é fácil desenrolá-lo:

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

Ou avaliando expressões constantes nas últimas quatro declarações:

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

3

Esta é uma maneira muito simples de fazer isso;

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 obrigado por sua ajuda. Reescrevi a função com comentários para uso em um programa. Aumente 8 para mais bits (até 32 para um inteiro).

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

Se você não quiser nenhum laço, terá que escrevê-lo:

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

Conforme demonstrado aqui, isso também funciona em um 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

Usando std::bitset

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

É um método útil, mas há algo errado no exemplo. bitset <n>, n é o número de bits, então o uso de sizeof (int) está errado.
Jerry Chou de
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.