Захват n бит из байта

У меня небольшая проблема с захватом n бит из байта.

У меня есть целое число без знака. Пусть говорят, что наш номер в шестнадцатеричном формате равен 0x2A, что равно 42 в десятичной системе. В двоичном виде это выглядит так: 0010 1010. Как бы я захватил первые 5 бит, которые являются 00101 и следующие 3 бита, которые равны 010, и помещают их в отдельные целые числа?

Если бы кто-нибудь мог мне помочь, это было бы здорово! Я знаю, как извлечь из одного байта, что просто сделать

int x = (number >> (8*n)) & 0xff // n being the # byte

который я видел в другом сообщении при переполнении стека, но я не был уверен, как получить отдельные биты из байта. Если бы кто-нибудь мог мне помочь, это было бы здорово! Спасибо!

Ответ 1

Целые числа представляются внутри машины как последовательность бит; к счастью для нас, люди, языки программирования предоставляют механизм, чтобы показать нам эти числа в десятичной (или шестнадцатеричной), но это не изменяет их внутреннего представления.

Вы должны пересмотреть побитовые операторы &, |, ^ и ~, а также операторы сдвига << и >>, которые помогут вам понять, как решить такие проблемы.

Последние 3 бита целого числа:

x & 0x7

Пять бит, начиная с восьми последних бит:

x >> 3    // all but the last three bits
  &  0x1F // the last five bits.

Ответ 2

"захват" частей целочисленного типа в C работает следующим образом:

  • Вы переносите бит, который вы хотите, в самую низкую позицию.
  • Вы используете & для маскировки желаемых битов - они означают "копировать этот бит", нули означают "игнорировать"

Итак, в вашем примере. Пусть говорят, что число int x = 42;

первые 5 бит:

(x >> 3) & ((1 << 5)-1);

или

(x >> 3) & 31;

Чтобы получить три нижних бита:

(x >> 0) & ((1 << 3)-1)

или

x & 7;

Ответ 3

Предположим, что вы хотите, чтобы бит hi был сверху, и lo бит снизу. (5 и 3 в вашем примере)

top = (n >> lo) & ((1 << hi) - 1)
bottom = n & ((1 << lo) - 1)

Пояснение:

Для вершины сначала избавьтесь от младших бит (сдвиг вправо), затем замаскируйте оставшуюся маску "все" (если у вас есть двоичное число, например 0010000, вычитая один результат 0001111 - такое же количество 1, как у вас было 0 -s в исходном номере).

Для дна это то же самое, просто не нужно заботиться о начальном перемещении.

top = (42 >> 3) & ((1 << 5) - 1) = 5 & (32 - 1) = 5 = 00101b
bottom = 42 & ((1 << 3) - 1) = 42 & (8 - 1) = 2 = 010b

Ответ 4

Для этого вы можете использовать битовые поля. Бит-биты - это специальные структуры, в которых вы можете указать переменные в битах.

typedef struct {
  unsigned char a:5;
  unsigned char b:3;
} my_bit_t;

unsigned char c = 0x42;
my_bit_t * n = &c;
int first = n->a;
int sec = n->b;

Бит-поля более подробно описаны на http://www.cs.cf.ac.uk/Dave/C/node13.html#SECTION001320000000000000000

Очарование бит-полей - это то, что вам не нужно иметь дело с операторами сдвига и т.д. Обозначение довольно простое. Как всегда при манипулировании битами возникает проблема переносимости.

Ответ 5

просто избавиться от 8 * в вашем коде.

int input = 42;
int high3 = input >> 5;
int low5 = input & (32 - 1); // 32 = 2^5
bool isBit3On = input & 4; // 4 = 2^(3-1)

Ответ 6

int x = (number >> 3) & 0x1f;

даст вам целое число, в котором последние 5 бит представляют собой 8-4 бит number и нули в других битах.

Аналогично,

int y = number & 0x7;

даст вам целое число с последними 3 битами, установите последние 3 бита number и нули в остальных.