C ++: маска и биты декодирования

Я только что натолкнулся на функцию, которую не понимаю, и мне было интересно, не могли бы вы мне это объяснить.

unsigned long long x(unsigned long long value, int begin, int end)
{
unsigned long long mask = (1 << (end - begin)) - 1;
return (value >> begin) & mask;
}

Спасибо
uksz

2

Решение

Вышеуказанная функция служит в качестве маски для извлечения диапазона битов из числа. Это можно разбить на четыре этапа.

Первый шаг:

mask = 1UL << (end - begin)

<< логически сдвиги 1 слева end - begin биты. Поскольку бинарный файл 1 является 000001сдвиг на 3 будет соответствовать 001000,

Второй шаг:

mask = mask - 1

Из предыдущего шага мы установили, что маска в этой точке будет представлять собой последовательность нулей, затем единицу, а затем end - begin количество нулей. Вычитание 1 от такого числа приведет к end - begin наименее значимые биты 1со всем остальным как 0, Вычитание 1 из нашего предыдущего примера дает 000111,

Третий шаг:

value >> begin

Это логически сместит целевой номер (тот, из которого нам нужно извлечь биты) вправо на begin биты. Так как мы хотим, чтобы биты в диапазоне begin to endмы можем оставить удалить биты, прежде чем begin,

Четвертый шаг:

(value >> begin) & mask

Взятие символьного AND с маской приведет к первому begin - end биты смещенного числа извлекаются. Это потому что 0 & x = 0 а также 1 & x = x,

Как указано в другом ответе Вирсавии, следует позаботиться о том, чтобы написать 1UL, чтобы гарантировать, что число, смещаемое unsigned int, Остальное перенести int больше битов в этом int является неопределенным поведением. 1UL является unsigned long long int со значением 1,

4

Другие решения

Поведение функции не определено. Так должно быть

unsigned long long mask = (1ULL << (end - begin)) - 1;

1 является int буквально и применяя больше левых сдвигов, чем есть биты в этом int является неопределенным поведением. 1ULL это неподписанный длинный длинный литерал.

Как только это будет исправлено, он надежно вернет только 0 и 1 бит в диапазоне начала и конца, и 0 везде.

4

Первая строка смещает влево число на количество (конец — начало) битовых сдвигов.
Вторая строка сдвигается вправо на количество (правых) битовых сдвигов.
Таким образом, в конце у вас будет маска, равная битам между «началом» и «концом».

1

(1) 1 in the expression implies 32 bit number on 32 bit machines.
So we need uul after 1 to make it 64 bit. Will work for MOST of the
cases.
unsigned long long mask = (1ull << (end - begin)) - 1;

(2) When begin=0, end=63, we will still see the wrong mask in case#1
The mask will come out be 0x7FFFFFFFFFFFFFFF
The following will fix that problem as well.
unsigned long long mask = ((1ull << end) - (1ull << begin)) | (1ull << end);

This will generate the mask 0xFFFFFFFFFFFFFFFF
1
По вопросам рекламы [email protected]