Jak uzyskać dane bit po bicie z wartości całkowitej w języku C?

99

Chcę wyodrębnić bity liczby dziesiętnej.

Na przykład 7 jest binarne 0111 i chcę uzyskać 0 1 1 1 wszystkie bity przechowywane w bool. Jak mogę to zrobić?

OK, pętla nie jest dobrą opcją, czy mogę zrobić coś innego?

Badr
źródło

Odpowiedzi:

154

Jeśli chcesz k-tego bitu n, zrób

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

Tutaj tworzymy maskę, nakładamy maskę na n, a następnie przesuwamy w prawo zamaskowaną wartość, aby uzyskać tylko ten bit, który chcemy. Moglibyśmy to opisać pełniej jako:

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

Możesz przeczytać więcej o maskowaniu bitów tutaj .

Oto program:

#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");
}
palec wskazujący
źródło
70
(n >> k) & 1jest równie poprawny i nie wymaga obliczania maski, ponieważ maska ​​jest stała z powodu przesunięcia przed maskowaniem zamiast na odwrót.
Joe
@Joe, czy możesz to wyjaśnić, może w odpowiedzi, proszę?
Dan Rosenstark
1
@Yar rozszerzył nieco mój komentarz i dodał nową odpowiedź zgodnie z prośbą
Joe
Podczas korzystania ze znanych bitów do celów informacyjnych (np. W przypadku protokołów sieciowych, takich jak Websockets), rzutowanie danych na urządzenie structmoże być również przydatne, ponieważ wszystkie wymagane dane uzyskuje się za pomocą jednej operacji.
Myst
@forefinger, czy możesz opublikować przykładowe wyjście kodu.
Ashish Ahuja
83

Zgodnie z prośbą, zdecydowałem się rozszerzyć swój komentarz na temat odpowiedzi palca wskazującego na pełną odpowiedź. Chociaż jego odpowiedź jest prawidłowa, jest niepotrzebnie złożona. Ponadto wszystkie aktualne odpowiedzi używają znaku ints do reprezentowania wartości. Jest to niebezpieczne, ponieważ przesunięcie wartości ujemnych w prawo jest określone przez implementację (tj. Nie jest przenośne), a przesunięcie w lewo może prowadzić do nieokreślonego zachowania (patrz to pytanie ).

Przesuwając w prawo żądany bit do najmniej znaczącej pozycji bitu, można wykonać maskowanie 1. Nie ma potrzeby obliczania nowej wartości maski dla każdego bitu.

(n >> k) & 1

Jako kompletny program oblicza (a następnie drukuje) tablicę wartości jednobitowych:

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

Zakładając, że chcesz obliczyć wszystkie bity tak jak w tym przypadku, a nie konkretny, pętlę można dalej zmienić na

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

To modyfikuje się inputna miejscu, a tym samym pozwala na użycie jednobitowego przesunięcia o stałej szerokości, co może być bardziej wydajne na niektórych architekturach.

Joe
źródło
5

Oto jeden sposób, aby to zrobić - jest wiele innych:

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

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

Trudno zrozumieć, dlaczego użycie pętli nie jest pożądane, ale łatwo ją rozwinąć:

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

Lub oceniając stałe wyrażenia w ostatnich czterech instrukcjach:

b [0] =  0 != (v & 1);
b [1] =  0 != (v & 2);
b [2] =  0 != (v & 4);
b [3] =  0 != (v & 8);
wallyk
źródło
3

Oto bardzo prosty sposób na zrobienie tego;

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;
}
d3vdpro
źródło
1

@prateek dziękuję za pomoc. Przepisałem funkcję z komentarzami do użycia w programie. Zwiększ 8, aby uzyskać więcej bitów (do 32 dla liczby całkowitej).

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;
}
ksinthose
źródło
1

Jeśli nie chcesz żadnych pętli, musisz to zapisać:

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

Jak pokazano tutaj, działa to również w inicjatorze.

wildplasser
źródło
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;
}
zaraz
źródło
0

Za pomocą std::bitset

int value = 123;
std::bitset<sizeof(int)> bits(value);
std::cout <<bits.to_string();
Smit Ycyken
źródło
To przydatna metoda, ale w przykładzie coś jest nie tak. bitset <n>, n to liczba bitów, więc użycie sizeof (int) jest nieprawidłowe.
Jerry Chou