Подтвердить что ты не робот

Как извлечь определенные "n" биты 32-разрядного целого числа без знака в C?

Может ли кто-нибудь сказать мне, как извлечь "n" конкретные биты из 32-разрядного целого числа без знака в C.

Например, скажем, мне нужны первые 17 бит 32-битного значения; что я должен делать?
Я предполагаю, что я должен использовать оператор модуля, и я попробовал его и смог получить последние 8 бит и последние 16 бит как

unsigned last8bitsvalue=(32 bit integer) % 16
unsigned last16bitsvalue=(32 bit integer) % 32

Это правильно? Есть ли лучший и эффективный способ сделать это?

4b9b3361

Ответ 1

Если вы хотите, чтобы n бит были конкретными, вы можете сначала создать битовую маску, а затем AND с вашим номером принять требуемые биты.

Простая функция для создания маски из бит a в бит b.

unsigned createMask(unsigned a, unsigned b)
{
   unsigned r = 0;
   for (unsigned i=a; i<=b; i++)
       r |= 1 << i;

   return r;
}

Вы должны проверить, что a <= b.

Если вы хотите, чтобы биты с 12 по 16 вызывали функцию, а затем просто и (логическое И) r с вашим номером N

r = createMask(12,16);
unsigned result = r & N;

Если вы хотите, вы можете сдвинуть результат. Надеюсь, что это поможет

Ответ 2

Вместо того, чтобы думать о нем как о "извлечении", мне нравится думать об этом как о "изоляции". Как только нужные биты будут изолированы, вы сможете делать то, что будете с ними.

Чтобы изолировать любой набор бит, примените маску AND.

Если вам нужны последние X бит значения, есть простой трюк, который можно использовать.

unsigned  mask;
mask = (1 << X) - 1;
lastXbits = value & mask;

Если вы хотите изолировать прогон X бит в середине "значения", начиная с "startBit"...

unsigned  mask;
mask = ((1 << X) - 1) << startBit;
isolatedXbits = value & mask;

Надеюсь, что это поможет.

Ответ 3

Модуль работает, чтобы получить нижние бит (только), хотя я думаю, что value & 0x1ffff выражает "принимать нижние 17 бит" более непосредственно, чем value % 131072, и поэтому это легче понять, как это делает.

Верхние 17 бит 32-разрядного значения без знака будут value & 0xffff8000 (если вы хотите, чтобы они все еще находились в своих позициях вверху) или value >> 15, если вы хотите, чтобы верхние 17 бит значения в нижней части 17 бит результата.

Ответ 4

Если вам нужны X последних бит вашего целого числа, используйте двоичную маску:

unsigned last8bitsvalue=(32 bit integer) & 0xFF
unsigned last16bitsvalue=(32 bit integer) & 0xFFFF

Ответ 5

Побитовое И ваше целое число с маской, имеющей точно те биты, которые вы хотите извлечь. Затем сдвиньте результат вправо, чтобы поместить извлеченные биты, если это необходимо.

unsigned int lowest_17_bits = myuint32 & 0x1FFFF;
unsigned int highest_17_bits = (myuint32 & (0x1FFFF << (32 - 17))) >> (32 - 17);

Изменить: последний устанавливает самые высокие 17 бит как самые низкие 17; это может быть полезно, если вам нужно извлечь целое число из "внутри" большего. Вы можете опустить правый сдвиг (>>), если это нежелательно.

Ответ 6

Существует один BEXTR (извлечение битового поля (с регистром)) инструкция x86 для процессоров Intel и AMD и UBFX в ARM. Существуют внутренние функции, такие как _bextr_u32() (ссылка требует входа), которые позволяют явно вызывать эту инструкцию.

Они реализуют (source >> offset) & ((1 << n) - 1) C-код: get n непрерывные биты от source, начиная с бит offset. Здесь полное определение функции, которое обрабатывает случаи краев:

#include <limits.h>

unsigned getbits(unsigned value, unsigned offset, unsigned n)
{
  const unsigned max_n = CHAR_BIT * sizeof(unsigned);
  if (offset >= max_n)
    return 0; /* value is padded with infinite zeros on the left */
  value >>= offset; /* drop offset bits */
  if (n >= max_n)
    return value; /* all  bits requested */
  const unsigned mask = (1u << n) - 1; /* n '1 */
  return value & mask;
}

Например, чтобы получить 3 бит из 2273 (0b100011100001), начиная с 5 -th бит, вызовите getbits(2273, 5, 3) -it извлекает 7 (0b111).

Например, скажем, мне нужны первые 17 бит 32-битного значения; что я должен делать?

unsigned first_bits = value & ((1u << 17) - 1); // & 0x1ffff

Предполагая, что CHAR_BIT * sizeof(unsigned) равно 32 в вашей системе.

Я предполагаю, что я должен использовать оператор модуля, и я попробовал его и смог получить последние 8 бит и последние 16 бит

unsigned last8bitsvalue  = value & ((1u <<  8) - 1); // & 0xff
unsigned last16bitsvalue = value & ((1u << 16) - 1); // & 0xffff

Если смещение всегда равно нулю, как и во всех ваших примерах в вопросе, тогда вам не нужен более общий getbits(). Существует специальная команда BLSMSK cpu, которая помогает вычислить маску ((1 << n) - 1).

Ответ 7

Это более краткий вариант принятого ответа: нижеприведенная функция извлекает биты от-до включительно, создавая битовую маску. После применения логики И над исходным номером результат сдвигается, поэтому функция возвращает только извлеченные биты. Пропущенные проверки индекса/целостности для ясности.

uint16_t extractInt(uint16_t orig16BitWord, unsigned from, unsigned to) 
{
  unsigned mask = ( (1<<(to-from+1))-1) << from;
  return (orig16BitWord & mask) >> from;
}

Ответ 8

#define GENERAL__GET_BITS_FROM_U8(source,lsb,msb) \
    ((uint8_t)((source) & \
        ((uint8_t)(((uint8_t)(0xFF >> ((uint8_t)(7-((uint8_t)(msb) & 7))))) & \
             ((uint8_t)(0xFF << ((uint8_t)(lsb) & 7)))))))

#define GENERAL__GET_BITS_FROM_U16(source,lsb,msb) \
    ((uint16_t)((source) & \
        ((uint16_t)(((uint16_t)(0xFFFF >> ((uint8_t)(15-((uint8_t)(msb) & 15))))) & \
            ((uint16_t)(0xFFFF << ((uint8_t)(lsb) & 15)))))))

#define GENERAL__GET_BITS_FROM_U32(source,lsb,msb) \
    ((uint32_t)((source) & \
        ((uint32_t)(((uint32_t)(0xFFFFFFFF >> ((uint8_t)(31-((uint8_t)(msb) & 31))))) & \
            ((uint32_t)(0xFFFFFFFF << ((uint8_t)(lsb) & 31)))))))