Come ottengo dati bit per bit da un valore intero in C?


99

Voglio estrarre bit di un numero decimale.

Ad esempio, 7 è binario 0111 e voglio ottenere 0 1 1 1 tutti i bit memorizzati in bool. Come posso farlo?

OK, un ciclo non è una buona opzione, posso fare qualcos'altro per questo?

Risposte:


154

Se vuoi il k-esimo bit di n, allora fallo

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

Qui creiamo una maschera, applichiamo la maschera a n, quindi spostiamo a destra il valore mascherato per ottenere solo il bit che vogliamo. Potremmo scriverlo in modo più completo come:

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

Puoi leggere di più sul mascheramento dei bit qui .

Ecco un programma:

#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è ugualmente valido e non richiede il calcolo della maschera in quanto la maschera è costante a causa dello spostamento prima della mascheratura invece del contrario.
Joe

@ Joe puoi spiegarlo, forse in una risposta, per favore?
Dan Rosenstark

1
@Yar ha esteso un po 'il mio commento e ha aggiunto una nuova risposta come richiesto
Joe

Quando si utilizzano bit noti per le informazioni (ad esempio per i protocolli di rete, come Websocket), anche il casting dei dati su a structpuò essere utile, poiché si ottengono tutti i dati richiesti con una singola operazione.
Myst

@forefinger, puoi inviare un output di esempio del codice.
Ashish Ahuja

83

Come richiesto, ho deciso di estendere il mio commento sulla risposta dell'indice a una risposta a tutti gli effetti. Sebbene la sua risposta sia corretta, è inutilmente complessa. Inoltre tutte le risposte correnti utilizzano ints con segno per rappresentare i valori. Questo è pericoloso, poiché lo spostamento a destra dei valori negativi è definito dall'implementazione (cioè non portabile) e lo spostamento a sinistra può portare a un comportamento indefinito (vedere questa domanda ).

Spostando a destra il bit desiderato nella posizione del bit meno significativo, è possibile eseguire il mascheramento 1. Non è necessario calcolare un nuovo valore di maschera per ogni bit.

(n >> k) & 1

Come programma completo, calcola (e successivamente stampa) un array di valori a bit singolo:

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

Supponendo che si desideri calcolare tutti i bit come in questo caso, e non uno specifico, il ciclo può essere ulteriormente modificato in

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

Ciò modifica inputin posizione e quindi consente l'uso di una larghezza costante, spostamento di un bit, che può essere più efficiente su alcune architetture.


5

Ecco un modo per farlo, ce ne sono molti altri:

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

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

È difficile capire perché l'uso di un loop non è desiderato, ma è abbastanza facile srotolare il loop:

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 valutare le espressioni costanti nelle ultime quattro affermazioni:

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

3

Ecco un modo molto semplice per farlo;

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 grazie per il tuo aiuto. Ho riscritto la funzione con commenti da utilizzare in un programma. Aumenta 8 per più bit (fino a 32 per un numero intero).

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 non vuoi alcun loop, dovrai scriverlo:

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

Come dimostrato qui, funziona anche in un inizializzatore.


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

Utilizzando std::bitset

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

È un metodo utile, ma nell'esempio c'è qualcosa di sbagliato. bitset <n>, n è il numero di bit, quindi l'uso di sizeof (int) è sbagliato.
Jerry Chou
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.