Русская Википедия:Битовое поле (C++)

Материал из Онлайн справочника
Версия от 05:26, 5 августа 2023; EducationBot (обсуждение | вклад) (Новая страница: «{{Русская Википедия/Панель перехода}} {{нет ссылок|дата=2010-01-21}} {{чистить|дата=2010-01-21}} '''Би́товое поле''' ({{lang-en|bit field}}) в программировании — некоторое количество бит, расположенных последовательно в памяти. == Об...»)
(разн.) ← Предыдущая версия | Текущая версия (разн.) | Следующая версия → (разн.)
Перейти к навигацииПерейти к поиску

Шаблон:Нет ссылок Шаблон:Чистить Би́товое поле (Шаблон:Lang-en) в программировании — некоторое количество бит, расположенных последовательно в памяти.

Об аппаратных реализациях

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

Файл:Computer system bus.svg
  • CPU (Шаблон:Lang-en) — центральный процессор.
  • Memory — оперативное запоминающее устройство (ОЗУ).
  • Input and output — другие устройства ввода-вывода.
  • Control bus — шина управления.
  • Address bus — шина адреса.
  • Data bus — шина данных.
  • System bus — системная шина.
  • Прочитанное значение равно значению, находящемуся в указанной ячейке памяти, и имеет размер, равный разрядности шины данных (размеру машинного слова).

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

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

    Пример. Пусть:

    0011 0100 1010 1110 0100 0111 0100 11002
    • требуется прочитать биты, выделенные жирным шрифтом.
    1. Процессор прочитает из памяти машинное слово, равное исходному значению:
    0011 0100 1010 1110 0100 0111 0100 11002
    1. С помощью инструкции and в биты, не входящие в битовое поле, будут записаны значения 0. Результат:
    0000 0000 0000 0010 0100 0000 0000 00002
    1. С помощью инструкции shr биты битового поля будут сдвинуты слева направо так, чтобы младший бит битового поля стал младшим битом машинного слова. Результат:
    0000 0000 0000 0000 0000 0000 0000 10012

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

    Пример. Пусть:

    0011 0100 1010 1110 0100 0111 0100 11002
    0011 0100 1010 1110 0100 0111 0100 11002
    • требуется прочитать биты, выделенные жирным шрифтом и расположенные по не выровненному адресу.
    1. Процессор прочитает из памяти два машинных слова, содержащих нужные биты; значения равны исходным:
    0011 0100 1010 1110 0100 0111 0100 11002
    0011 0100 1010 1110 0100 0111 0100 11002
    1. С помощью двух инструкций and в биты, не входящие в битовое поле, будут записаны значения 0. Результат:
    0000 0000 0000 0000 0000 0001 0100 11002
    0011 0100 0000 0000 0000 0000 0000 00002
    1. С помощью инструкции shr биты второго машинного слова будут сдвинуты слева направо так, чтобы младший бит битового поля стал младшим битом машинного слова. С помощью инструкции shl биты первого машинного слова будут сдвинуты справа налево так, чтобы освободить младшие разряды для бит второго машинного слова (для следующего шага). Результат:
    0000 0000 0000 0000 0101 0011 0000 00002
    0000 0000 0000 0000 0000 0000 0000 11012
    1. С помощью инструкции or биты двух машинных слов будут «наложены» друг на друга. Результат:
    0000 0000 0000 0000 0101 0011 0000 11012

    Описанные дополнительные действия могут выполняться:

    Недостаток: дополнительные команды замедляют выполнение программы. Достоинство: при использовании битовых полей достигается максимально плотная упаковка информации.

    О компиляторах

    Компиляторы, как правило, позволяют выполнять с битовыми полями только следующие операции:

    • чтение значения из битового поля;
    • запись значения в битовое поле.

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

    Применение

    Битовые поля применяются для максимально полной упаковки информации, если не важна скорость доступа к этой информации. Например, для увеличения пропускной способности канала при передаче информации по сети или для уменьшения размера информации при хранении. Также использование битовых полей оправдано, если процессор поддерживает специализированные инструкции для работы с битовыми полями, а компилятор использует эти инструкции при генерировании машинного кода.

    Например, на машинах с 32-битовым словом все поля IPv4-пакета (кроме полей «адрес отправителя» и «адрес получателя») будут битовыми полями, так как их размер не равен 32 битам и их адреса не кратны 4 байтам. Если, в дополнение к этому, процессор поддерживает прямое чтение и запись 8- и 16-битовых чисел, битовыми полями будут только поля «версия», «размер заголовка», «DSCP», «ECN», флаги и «смещение фрагмента».

    Операции над многобитовыми полями

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

    • битовые поля a и b, занимающие по одному биту;
    • битовое поле c, занимающее 2 бита;
    • битовое поле d, занимающее 4 бита.
    Номер бита 7[* 1] 6 5 4 3 2 1 0[* 2]
    Битовое поле d c b a
    Шаблон:Примечания

    Значение восьмибитового числа x, составленного из битовых полей a, b, c и d, можно вычислить по формуле: <math> x = a \cdot 2^0 + b \cdot 2^1 + c \cdot 2^2 + d \cdot 2^4 </math> Шаблон:Якорь2.

    Если a=1, b=0, c=2=102 и d=5=01012, число x будет равно <math>x = \underbrace{0101}_{d}\underbrace{10}_{c}\underbrace{0}_{b}\underbrace{1}_{a} = 1 \cdot 2^0 + 0 \cdot 2^1 + 2 \cdot 2^2 + 5 \cdot 2^4 = 89</math>.

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

    Если процессор оперирует двоичными числами, формула (1) может быть оптимизирована. После замены операций «возведение в степень» на «логический сдвиг», «сложение» на «битовое ИЛИ» формула (1) примет вид:

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

    Логический сдвиг двоичного числа эквивалентен умножению/делению на число, кратное степени двойки: 21=2, 22=4, 23=8 и т. д.

    Извлечение битового поля

    Получить значение v некоторого битового поля числа x можно двумя способами:

    При первом способе сначала выполняется операция «битовое И», затем — логический сдвиг вправо. При втором способе операции выполняются в обратном порядке. Константа mask_2 может быть получена из константы mask_1:
    Шаблон:Cpp.
    offset — номер первого младшего бита битового поля v, показатель степени в формуле (1).

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

    1. вычисляют «битовую маску» mask_1 — число, у которого в соответствующих битовому полю разрядах установлены единицы, а в остальных разрядах — нули;
    Номер бита 7 6 5 4 3 2 1 0
    Маска для a 0 0 0 0 0 0 0 1
    Маска для b 0 0 0 0 0 0 1 0
    Маска для c 0 0 0 0 1 1 0 0
    Маска для d 1 1 1 1 0 0 0 0
    1. умножают «битовую маску» на число с помощью операции «битовое И»;
    2. выполняют логический сдвиг вправо на offset бит.
    Битовое поле offset
    a 0
    b 1
    c 2
    d 4

    Пример получения значения из битового поля c:

    c = ( x & 00001100b ) >> 2
    

    При втором способе:

    1. выполняют логический сдвиг вправо;
    2. вычисляют «битовую маску» mask_2 — число, у которого в первых n младших разрядах установлены единицы, а остальных разрядах — нули; n — число разрядов битового поля;
    Номер бита 7 6 5 4 3 2 1 0
    Маска для a 0 0 0 0 0 0 0 1
    Маска для b 0 0 0 0 0 0 0 1
    Маска для c 0 0 0 0 0 0 1 1
    Маска для d 0 0 0 0 1 1 1 1
    1. умножают «битовую маску» на число с помощью операции «битовое И».

    Пример получения значения из битового поля c:

    c = ( x >> 2 ) & 00000011b
    

    Для младшего битового поля (поля a в данном примере) логический сдвиг на ноль разрядов не выполняется. Пример:
    Шаблон:Cpp
    Шаблон:Cpp

    a = x & 00000001b
    

    При втором способе для старшего поля (поля d в данном примере) логическое умножение не выполняется, так как операция логического сдвига вправо добавляет в число нулевые биты. Пример:
    Шаблон:Cpp

    d = x >> 4
    

    Замена битового поля

    Для замены битового поля выполняют три операции:

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

    Пример замены значения для битового поля d:

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

    Операции над однобитовыми полями

    Для работы с битовыми полями шириной в один бит существуют более простые методы.

    Битовые поля a и b занимают по одному биту.

    Проверка отдельного бита

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

    Пример получения значения однобитового поля b:

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

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

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

    Для проверки равенства единице всех бит из группы используют «побитовое И» и операцию «==»:

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

    Установка битов

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

    Пример установки бита однобитового поля a:

    x1 = x | 00000001b
    

    Для установки нескольких битов числа x, например, битов однобитовых полей a и b, используют маску, у которой в битах, соответствующих битам битовых полей, установлены единицы:

    x2 = x | 00000011b
    

    Снятие битов

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

    Пример установки нулей в биты битового поля b:

    x3 = x & 11111101b
    

    Переключение битов

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

    Пример изменения значений бит битового поля b:

    x4 = x ^ 00000010b
    

    Операции над знаковыми полями в дополнительном коде

    В памяти компьютера целые отрицательные числа могут кодироваться одним из следующих способов:

    Большинство современных процессоров реализуют третий способ. Рассмотрим двоичное представление нескольких целых чисел в дополнительном коде:

     4 = 000001002
     3 = 000000112
     2 = 000000102
     1 = 000000012
     0 = 000000002
    -1 = 111111112
    -2 = 111111102
    -3 = 111111012
    -4 = 111111002
    и т. д.
    

    Пусть поля 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 всё наоборот: знаком Шаблон:Cpp обозначается арифметический сдвиг, а знаком Шаблон:Cpp — логический.

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

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

    Объявления битовых полей

    В языках C и C++ при объявлении (Шаблон:Lang-en) битового поля используется [[Двоеточие|символ двоеточия Шаблон:Symbol]]. После двоеточия указывается константное выражение, определяющее количество битов в битовом поле[1]. Пример:

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

    См. также

    Примечания

    Шаблон:Примечания


    Ошибка цитирования Для существующих тегов <ref> группы «*» не найдено соответствующего тега <references group="*"/>