Menu

Манипулирование битами

Отличным примером способности D генерировать код во время компиляции при помощи mixin'ов является манипулирование битами.

Простое манипулирование битами

D предоставляет следующие операторы для манипулирования битами:

  • & побитовое "и"
  • | побитовое "или"
  • ~ побитовое отрицание
  • << побитовый знаковый сдвиг влево
  • >> побитовый знаковый сдвиг вправо (сохраняет знак в старшем бите)
  • >>> побитовый беззнаковый сдвиг вправо

На практике

Часто встречающийся пример работы с битами - чтение значения одного бита. D предоставляет core.bitop.bt для наиболее часто встречающихся задач, однако для начала, чтобы привыкнуть к работе с битами, давайте рассмотрим полную реализацию методики проверки значения бита:

enum posA = 1;
enum maskA = (1 << posA);
bool getFieldA()
{
    return _data & maskA;
}

Обобщением данной задачи является проверка блоков длиной более 1. Для этого потребуется специальная маска требуемой длины и соответствующий сдвиг блока перед наложением маски:

enum posA = 1;
enum lenA = 3;
enum maskA = (1 << lenA) - 1; // ...0111
uint getFieldA()
{
    return (_data >> posA) & maskA;
}

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

void setFieldA(bool b);
{
    return (_data & ~maskAWrite) | ((b << aPos) & maskAWrite);
}

std.bitmanip на помощь

Конечно, всегда весело работать с битами вручную, и D предлагает для этого полный набор инструментов. Однако в большинстве случаев такой код придётся постоянно копировать, а это чревато ошибками и с трудом поддаётся поддержке. И здесь на помощь приходит модуль std.bitmanip, позволяющий писать поддерживаемый, легко читаемый код, управляющий битами, посредством мощного механизма mixin'ов, не теряя при этом в производительности.

Взгляните на раздел с упражнениями. В нём определён BitVector, который использует лишь X битов, но при этом едва отличается от обыкновенной структуры.

Модули std.bitmanip и core.bitop предоставляют значительный объём вспомогательного кода для приложений, требующих малого потребления памяти.

Отступ и выравнивание

Поскольку компилятор будет добавлять отступы для переменных размером меньше, чем определено схемой размещения в текущей OS (size_t.sizeof), например для типов bool, byte, char, рекомендуется начинать с полей с бо́льшим выравниванием.

Подробнее

rdmd playground.d