Битовое поле

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

Битовое поле — в программировании число, занимающее некоторый набор битов, напрямую не адресуемый процессором. Например: при 8-битном байте первые два поля протокола IP — версия и IHL — будут битовыми полями. На машинах с 32-битным байтом все поля IP-пакета (кроме IP-адресов отправителя и получателя) будут битовыми.

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

Компиляторы, как правило, ограничивают работу с битовыми полями только извлечением значения битового поля и записью значения в битовое поле, а само битовое поле воспринимается как беззнаковое число. Реальный порядок следования битовых полей в структуре является системно-зависимым: в одних компиляторах битовые поля могут быть расположены начиная с младших битов, а в других — со старших.

Операции над многобитовыми полями[править | править вики-текст]

Пусть в одном байте находятся четыре битовых поля:

  • 1-о битовые поля a и b;
  • 2-х битовое поле c;
  • 4-х битовое поле d.

То есть x = a \cdot 2^0 + b \cdot 2^1 + c \cdot 2^2 + d \cdot 2^4.

 [старший бит] d d d d c c b a [младший бит]

Например, при a=1, b=0, c=2=102, d=5=01012 получаем x=010110012=89.

Сборка одного числа из битовых полей[править | править вики-текст]

Двоичные компьютеры обычно имеют команды побитового сдвига, которые позволяют быстро выполнять умножение на числа, равные степени двойки — 2, 4, 8 и т. д. Вместо сложения можно применить команду логического «ИЛИ». Таким образом, число x можно собрать и по-другому:

x = (d << 4) | (c << 2) | (b << 1) | a

Извлечение битового поля[править | править вики-текст]

Для извлечения битового поля нужно провести две операции:

  1. умножить операцией логического «И» число на битовую маску — число, у которого в соответствующих разрядах единицы, а в остальных нули;
  2. провести побитовый сдвиг вправо.

То есть:

c = ( x & 00001100b ) >> 2

Либо:

  1. провести побитовый сдвиг вправо;
  2. умножить операцией логического «И» число на битовую маску соответствующей длины.
c = ( x >> 2 ) & 00000011b

Для младшего поля побитовый сдвиг не нужен, то есть:

a = x & 00000001b

Для старшего поля побитовый сдвиг сам по себе, без умножения на маску, очистит x от ненужных битов — то есть,

d = x >> 4

Замена битового поля[править | править вики-текст]

Для замены битового поля нужно провести две операции:

  1. очистить x от предыдущего значения побитовым умножением на маску с нулями в соответствующих битах;
  2. побитово сложить x с новым значением (сдвинутым на нужное количество битов).

Например, если нужно заменить d, то

xnew = ( x & 00001111b ) | ( d << 4 )

Операции над однобитовыми полями[править | править вики-текст]

Поля a и b имеют длину 1 бит — это позволяет работать с ними несколько другими средствами.

Проверка отдельного бита[править | править вики-текст]

Для проверки надо побитово умножить x операцией «И» на маску, у которой одна единица — в соответствующей позиции. Если получился 0, бит равен 0.

b = ((x & 00000010b) != 0)

Проверка, равен ли единице хотя бы один бит из нескольких:

a_or_b = ((x & 00000011b) != 0)

Проверка, равны ли единице все биты из нескольких:

a_and_b = ((x & 00000011b) == 00000011b)

Установка битов[править | править вики-текст]

Для этого надо сложить операцией «ИЛИ» x с маской, у которой единицы в соответствующих позициях. Например, чтобы включить бит a:

x1 = x | 00000001b

Чтобы включить и a, и b:

x2 = x | 00000011b

Снятие битов[править | править вики-текст]

Чтобы снять один или несколько битов, надо сложить x операцией «И» с маской, у которой в соответствующих позициях нули. В частности, чтобы выключить бит b, нужно дать команду:

x3 = x & 11111101b

Переключение битов[править | править вики-текст]

Для переключения битов (с 0 на 1, с 1 на 0) надо сложить x командой «Исключающее ИЛИ» с маской, у которой в соответствующих позициях единицы. Например, бит b переключается так:

x4 = x ^ 00000010b

Операции над знаковыми полями в дополнительном коде[править | править вики-текст]

Существуют два способа хранения отрицательных целых чисел — знаковый бит и дополнительный код. В подавляющем большинстве современных машин применяется второй. При записи отрицательных чисел дополнительным кодом имеем:

-1 = 11111111b
-2 = 11111110b
-3 = 11111101b
-4 = 11111100b
и т. д.

Считаем, что поля c и d имеют именно такой формат. Тогда поле c может хранить числа от −2=102 до 1=012, а поле d — от −8=10002 до 7=01112.

Сборка и замена чисел[править | править вики-текст]

Каждое из слагаемых (кроме старшего), чтобы оно не испортило более старшие разряды, требуется умножать на битовую маску соответствующей длины. В частности:

x = (d << 4) + ((c & 00000011b) << 2) + (b << 1) + a

Извлечение чисел[править | править вики-текст]

Для извлечения чисел требуется сдвинуть поле на нужное количество битов вправо, заодно размножив знаковый бит. Например, для этого можно воспользоваться арифметическим сдвигом. Если x имеет длину 8 битов, то

c = (x << 4 ) >>a 6
d = x >>a 4

Внимание! В языке программирования Java всё наоборот: знаком >> обозначается арифметический сдвиг, знаком >>> — простой.

Если арифметического сдвига нет, то…

c1 = x >> 2
если (c1 & 00000010b ≠ 0)
  то c = c1 | 0x11111100b
  иначе c = c1 & 0x00000011b

Объявления битовых полей[править | править вики-текст]

В языке C/C++[править | править вики-текст]

В декларации битового поля используется двоеточие, за которым следует константное выражение определяющее количество битов в поле[1];

struct rgb
{
    unsigned r:3;
    unsigned g:3;
    unsigned b:3;
};

Примечания[править | править вики-текст]

  1. Рэй Лишнер [[1] С++. Справочник] = C++ In a Nutshell / гл. ред. Е. Строгонова. — СПб.: Питер, 2003. — С. 193. — 907 с. — 3 500 экз. — ISBN 5-94723-928-0, ББК 32.973-018.1я22, УДК 681.3.06(03).