Как мне получить побитовые данные из целочисленного значения в C?


100

Я хочу извлечь биты десятичного числа.

Например, 7 - это двоичный 0111, и я хочу получить 0 1 1 1 все биты, хранящиеся в bool. Как я могу это сделать?

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

Ответы:


155

Если вам нужен 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 немного расширил мой комментарий и добавил новый ответ по запросу
Джо

При использовании известных битов для информации (например, для сетевых протоколов, таких как Websockets), преобразование данных в объект также structможет быть полезным, поскольку вы получаете все необходимые данные за одну операцию.
Myst

@forefinger, не могли бы вы опубликовать пример вывода кода.
Ашиш Ахуджа

85

По просьбе, я решил расширить свой комментарий к ответу указательного пальца до полноценного ответа. Хотя его ответ правильный, он излишне сложен. Кроме того, все текущие ответы используют подписанные 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.