Bagaimana cara mendapatkan data bit-demi-bit dari nilai integer di C?


99

Saya ingin mengekstrak bit dari bilangan desimal.

Misalnya, 7 adalah biner 0111, dan saya ingin 0 1 1 1 semua bit disimpan dalam bool. Bagaimana saya bisa melakukannya?

Oke, loop bukanlah pilihan yang baik, dapatkah saya melakukan hal lain untuk ini?

Jawaban:


154

Jika Anda menginginkan bit k-th dari n, lakukan

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

Di sini kita membuat mask, menerapkan mask ke n, lalu geser ke kanan nilai mask untuk mendapatkan sedikit yang kita inginkan. Kita dapat menuliskannya lebih lengkap sebagai:

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

Anda dapat membaca lebih lanjut tentang bit-masking di sini .

Berikut adalah programnya:

#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) & 1sama validnya dan tidak perlu menghitung topeng karena topengnya konstan karena bergeser sebelum menutupi alih-alih sebaliknya.
Joe

@Joe bisakah Anda menjelaskan itu, mungkin dalam sebuah jawaban, tolong?
Dan Rosenstark

1
@Yar memperpanjang komentar saya sedikit dan menambahkan jawaban baru seperti yang diminta
Joe

Saat menggunakan bit yang diketahui untuk informasi (misalnya untuk protokol jaringan, seperti Websockets), mentransmisikan data ke a structjuga dapat berguna, karena Anda mendapatkan semua data yang diperlukan dengan satu operasi.
Myst

@forefinger, dapatkah Anda memposting contoh keluaran kode.
Ashish Ahuja

83

Seperti yang diminta, saya memutuskan untuk memperpanjang komentar saya pada jawaban telunjuk menjadi jawaban yang lengkap. Meskipun jawabannya benar, itu sangat rumit. Selanjutnya semua jawaban saat ini menggunakan tanda ints untuk mewakili nilai. Ini berbahaya, karena pergeseran kanan dari nilai-nilai negatif ditentukan oleh implementasi (yaitu tidak portabel) dan pergeseran ke kiri dapat menyebabkan perilaku yang tidak ditentukan (lihat pertanyaan ini ).

Dengan menggeser bit yang diinginkan ke kanan ke posisi bit yang paling tidak signifikan, masking dapat dilakukan dengan 1. Tidak perlu menghitung nilai topeng baru untuk setiap bit.

(n >> k) & 1

Sebagai program lengkap, menghitung (dan kemudian mencetak) larik nilai bit tunggal:

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

Dengan asumsi bahwa Anda ingin menghitung semua bit seperti dalam kasus ini, dan bukan bit tertentu, loop dapat diubah lebih lanjut menjadi

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

Ini memodifikasi inputdi tempat dan dengan demikian memungkinkan penggunaan lebar konstan, pergeseran bit tunggal, yang mungkin lebih efisien pada beberapa arsitektur.


5

Berikut salah satu cara untuk melakukannya — ada banyak cara lainnya:

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

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

Sulit untuk memahami mengapa penggunaan loop tidak diinginkan, tetapi cukup mudah untuk membuka 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));

Atau mengevaluasi ekspresi konstanta dalam empat pernyataan terakhir:

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

3

Berikut cara yang sangat sederhana untuk melakukannya;

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 terima kasih atas bantuannya. Saya menulis ulang fungsi dengan komentar untuk digunakan dalam sebuah program. Tingkatkan 8 untuk lebih banyak bit (hingga 32 untuk bilangan bulat).

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

Jika Anda tidak menginginkan loop apa pun, Anda harus menuliskannya:

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

Seperti yang ditunjukkan di sini, ini juga berfungsi di penginisialisasi.


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

Menggunakan std::bitset

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

Ini adalah metode yang berguna, tetapi ada yang salah dalam contoh. bitset <n>, n adalah banyaknya bit, sehingga penggunaan sizeof (int) salah.
Jerry Chou
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.