Як отримати побітні дані з цілого значення в C?


99

Я хочу витягнути біти десяткового числа.

Наприклад, 7 є двійковим 0111, і я хочу отримати 0 1 1 1 всі біти, що зберігаються в bool. Як я можу це зробити?

Гаразд, цикл - це не гарний варіант, чи можу я зробити для цього щось інше?

Відповіді:


154

Якщо ви хочете k-го шматочка n, тоді зробіть

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

Тут ми створюємо маску, застосовуємо маску до n, а потім зміщуємо масковане значення праворуч, щоб отримати просто потрібний біт. Ми могли б виписати це більш повно:

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

Детальніше про біт-маскування ви можете прочитати тут .

Ось програма:

#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однаково справедливий і не вимагає обчислення маски, оскільки маска є постійною через зміщення перед маскуванням, а не навпаки.
Джо

@ Джо, чи можете ви пояснити це, можливо, у відповіді, будь ласка?
Дан Розенстарк

1
@Yar трохи продовжив мій коментар і додав відповідь, як вимагається
Joe

Якщо ви використовуєте відомі біти для інформації (тобто для мережевих протоколів, таких як Websockets), також structможе бути корисним перенесення даних на a , оскільки ви отримуєте всі необхідні дані за одну операцію.
Міст

@forefinger, чи можете ви опублікувати приклад виводу коду.
Ашиш Ахуджа

83

На прохання я вирішив поширити свій коментар щодо відповіді вказівного пальця на повноцінну відповідь. Хоча його відповідь правильна, вона непотрібна. Крім того, всі поточні відповіді використовують підписані ints для представлення значень. Це небезпечно, оскільки зсув правого зміщення негативних значень визначено реалізацією (тобто не є переносним), а зміщення ліворуч може призвести до невизначеної поведінки (див. Це питання ).

Перемістивши потрібний біт у найменш значуще бітове положення, маскування можна зробити за допомогою 1. Не потрібно обчислювати нове значення маски для кожного біта.

(n >> k) & 1

Як повна програма, обчислюючи (а згодом друкуючи) масив єдиних бітових значень:

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

Припускаючи, що ви хочете обчислити всі біти, як у цьому випадку, а не конкретний, цикл можна додатково змінити на

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

Це змінюється inputна місці і тим самим дозволяє використовувати постійну ширину, однорозрядний зсув, що може бути більш ефективним для деяких архітектур.


5

Ось один із способів зробити це - є багато інших:

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

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

Важко зрозуміти, чому використання циклу не бажано, але досить просто розкрутити цикл:

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

Або оцінка постійних виразів в останніх чотирьох твердженнях:

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

3

Ось дуже простий спосіб зробити це;

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 дякую за допомогу. Я переписав функцію із коментарями для використання в програмі. Збільшити 8 для більшої кількості бітів (до 32 для цілого числа).

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

Якщо вам не потрібні петлі, вам доведеться виписати їх:

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

Як показано тут, це також працює в ініціалізаторі.


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

Використання std::bitset

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

Це корисний метод, але в прикладі щось не так. bitset <n>, n - кількість бітів, тому використання sizeof (int) неправильне.
Джеррі Чоу
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.