что такое битовое поле
Битовые поля в C++
Классы и структуры могут содержать члены, которые занимают меньше пространства в памяти, чем целочисленный тип. Эти члены определяются как битовые поля. Синтаксис для спецификации объявления члена в битовом поле приведен ниже:
Синтаксис
декларатор : константное выражение
Remarks
Декларатор (необязательный) — это имя, по которому осуществляется доступ к элементу в программе. Он должен иметь один из целочисленных типов (включая перечисляемые типы). Константа-выражение указывает количество битов, занимаемых элементом в структуре. Анонимные битовые поля, (т. е. битовые поля без идентификатора) можно использовать для заполнения.
В следующем примере объявляется структура, которая содержит битовые поля:
Структура памяти объекта типа Date
Блок, относящийся только к системам Microsoft
Данные, объявленные в качестве битовых полей, упорядочиваются от младшего бита к старшему, как показано на рисунке выше.
Завершение блока, относящегося только к системам Майкрософт
Объявление структуры может содержать неименованное поле длиной 0, как показано в следующем примере.
затем макет памяти показан на следующем рисунке:
Структура объекта типа Date с битовым полем нулевой длины
Базовый тип битового поля должен быть целочисленным типом, как описано в разделе встроенные типы.
Ограничения для битовых полей
В следующем списке указаны ошибочные операции с битовыми полями:
Получение адреса битового поля.
Инициализация не const ссылки с битовым полем.
C Урок 32. Битовые поля
Продолжаем работать со структурами.
Оказывается, кроме полей размером, кратным байту, мы можем в структурах (а также, конечно, и в объединениях) работать с битами, то есть мы можем объявить поле в какое-то количество бит. Хотя язык C не предусматривает операции с отдельным битом, но с помощью битовых полей это ограничение можно обойти. Это, конечно же, не является полной заменой битовых операций ассемблера, но для удобства работы с кодом, для его читабельности, мы это вполне можем применять.
Также, если мы и не будем в своих кодах применять битовые поля, то нам такое может попасться в чужих кодах, и после данного урока мы будем хотя бы знать, что это такое.
Также битовые поля нам могут потребоваться для каких-то флагов, для каких-то значений, диапазон которых отличается от диапазона стандартных типов.
Битовое поле в структуре объявляется следующим образом
В различной литературе я читал про разные ограничения типов для битовых полей. Видимо, всё это исходит из различных стандартов, выходящих время от времени. Поэкспериментировав немного, я понял, что самое главное, чтобы этот тип был целочисленным.
Если в структуре есть и битовые поля и обычные поля, то лучше битовые поля располагать подряд и стараться их не чередовать с обычными для того, чтобы меньше потребовалось памяти под структуру. Также по возможности выравнивание полей тоже лучше отключить. Можно и оставить, если, конечно, у нас в сумме размер всех битовых полей, идущих подряд в структуре будет стремиться к 32.
Вот пример объявления битовых полей в структуре, которой есть и обычные поля
#pragma pack(push, 1)
typedef struct
unsigned char diad0 :2;
unsigned char tri0 :3;
unsigned char bit0 :1;
unsigned char bit1 :1;
unsigned char a ;
unsigned short b ;
> my_arg_t ;
#pragma pack(pop)
Так как мы отключили выравнивание, то под переменную такой структуры будет выделена память в 4 байта.
Небольшое выравнивание в данном случае все равно произойдёт, так как если посчитать суммарное количество битов в битовых полях, то их у нас 7, а не 8, то есть если количество битов в непрерывно следующих битовых полях в структуре не кратно восьми, то следующее за ним небитовое обычное поле будет выравниваться по биту следующего адреса, так как адресоваться в битах мы не можем.
В случае конкретной структуры, которую мы только что объявили поля её расположатся в памяти следующим образом
Самые младшие два бита младшего байта заняло битовое поле (диада) diad0, следующие три бита этого же байта заняло битовое поле (триада) tri0, следующий бит этого байта – битовое поле размером в 1 бит bit0, следующий бит – такое же поле bit1. 7-й бит данного байта у нас не участвует в данных вообще, так как следующее поле не битовое. Поэтому следующее поле заняло следующий байт, а последнее поле – следующие 2 байта, сначала – младший байт поля, а затем – старший.
Думаю, теперь немного прояснилась картина по битовым полям.
Ну а чтобы она совсем прояснилась, давайте поработаем с ними на практике.
Поэтому давайте приступим к проекту, который мы сделаем, как всегда, из проекта прошлого урока с именем MYPROG31 и присвоим ему имя MYPROG32.
Откроем наш проект в Eclipse, произведём его первоначальную настройку и удалим весь наш код из функции main() за исключением возврата. Функция main() приобретёт вот такой вид
int main()
return 0; //Return an integer from a function
Глобальное объединение my_arg_t и одноимённую закомментированную структуру также удалим и добавим вместо них структуру с битовыми полями, точь в точь такую же, как в теоретической части
Объединения и битовые поля
Объединения
О бъединения в си похожи на структуры, с той разницей, что все поля начинаются с одного адреса. Это значит, что размер объединения равен размеру самого большого его поля. Так как все поля начинаются с одного адреса, то их значения перекрываются. Рассмотрим пример:
Здесь было создано объединение, которое содержит три поля – одно поле целого типа (4 байта), два поля типа short int (2 байта каждое) и 4 поля по одному байту. После того, как значение было присвоено полю dword, оно также стало доступно и остальным полям.
Напоминаю, что на x86 байты располагаются справа налево. Все поля объединения «обладают» одинаковыми данными, но каждое поле имеет доступ только до своей части.
Вот ещё один пример: рассмотрим представление числа с плавающей точкой:
Обратите внимание, что объединение можно инициализировать, как и структуру. При этом значение будет приводиться к типу, который имеет самое первое поле. Сравните результаты работы
Битовые поля
Битовые поля в си объявляются с помощью структур. Они позволяют получать доступ до отдельных битов или групп битов. Доступ до отдельных битов можно осуществлять и с помощью битовых операций, но использование битовых полей часто упрощает понимание программы.
Синтаксис объявления битового поля
В этом примере каждое поле структуры обозначено как битовое поле, длина каждого поля равна единице. Обращаться к каждому полю можно также, как и к полю обычной структуры. Битовые поля имеют тип unsigned int, так как имеют длину один бит. Если длина поля больше одного бита, то поле может иметь и знаковый целый тип.
Размер структуры, содержащей битовые поля, всегда кратен 8. То есть, если одно поле содержит 5 бит, а второе 4, то второе поле начинается с восьмого бита и три бита остаются неиспользованными.
Неименованное поле может иметь нулевой размер. В этом случае следующее за ним поле смещается так, чтобы добрать до 8 бит.
Если же адрес поля уже кратен 8 битам, то нулевое поле не добавит сдвига.
Кроме того, если имеются обычные поля и битовые поля, то первое битовое поле будет сдвинуто так, чтобы добрать до 8 бит.
Те же самые действия можно было сделать и с помощью обычного сдвига
Рассмотрим ещё один пример – знакопостоянный сдвиг вправо. Сдвиг вправо (>>) выталкивает самый левый бит и справа записывает ноль. Из-за этого операцию сдвига вправо нельзя применить, например, для чисел со знаком, так как будет потерян бит знака. Исправим ситуацию, сделаем знакопостоянный сдвиг: будем проверять последний бит числа (напомню, что мы работаем с архитектурой x86 и биты расположены «задом наперёд»)
Национальная библиотека им. Н. Э. Баумана
Bauman National Library
Персональные инструменты
Битовое поле
Битовое поле – это элемент структуры, определенный как некоторое число битов, обычно меньшее, чем число битов в целом числе (оно по величине не превосходит машинного слова и зависит от реализации компилятора). Они предназначены для экономного размещения в памяти данных небольшого диапазона, обеспечивают удобный доступ к отдельным битам данных. Кроме того, с помощью битовых полей можно формировать объекты с длиной внутреннего представления, не кратной байту. Битовые поля обычно применяются в низкоуровневом программировании. [Источник 1]
Значение отдельных битов в поле определяется программистом, например, первый бит в битовое поле (расположенном в поле базового адреса) иногда используется для определения состояния конкретного атрибута, связанного с битовым полем.
В микропроцессорах и других логических устройств, наборы бит поля «флаги» обычно используются для контроля или для обозначения промежуточного состояния или результатов конкретной деятельности. Микропроцессоры, как правило, имеют статус регистра, который состоит из таких флагов, используемые для обозначения различных состояния после операций, например, арифметическое переполнение. Флаги можно прочитать и используются для принятия решения о последующих операциях, например, при обработке условного скачка инструкции. Например, je (перейти если равно) инструкция на х86 ассемблере в результате скачка если Z (ноль) флаг был установлен на некоторую предыдущую операцию.
Битовое поле отличается от битового массива тем, что последний используется для хранения большой набор битов, пронумерованных целыми числами и часто шире, чем любой целочисленный тип поддерживаемых языков. Битовые поля, с другой стороны, как правило, помещается в машину, слово, и денотата бит не зависит от их числовым индексом.
Содержание
Применение
Битовые поля могут использоваться для уменьшения потребления памяти, когда программа требует ряд целочисленных переменных, которые всегда будут иметь низкие значения. Например, во многих системах хранения целочисленное значение требуется два байта (16 бит) памяти; иногда значения будут храниться только в одном или двух битах. Имея некоторые из этих крошечных переменные битового поля позволяет эффективно упаковывать данные в памяти. В C и C++, собственной реализации определенных битовые поля могут быть созданы, используя беззнаковый int, подписанный int, или (в c99:) _Bool. В этом случае, программист может объявить структуру битового поля метки и определяет ширину из нескольких подполей. При заявленной битовые поля того же типа могут быть упакованы компилятор в меньшее количество слов, по сравнению с памятью используется если в каждом «поле» будет объявлена отдельно. Для языков, не хватает родных полей, или где программист хочет строго контролировать результирующий бит представлении, можно вручную манипулировать битами в рамках более крупного типа Word. В этом случае программист может установить, проверить и изменить биты в поле с помощью комбинации маскировки и побитовые операции.
Компиляторы
Операции которые компиляторы могут произвести с битовыми полями довольно ограничены. Компиляторы способны лишь произвести чтение значения из битового поля, а также запись в битовое поле. Компиляторы распознают битовое поле как число без знака. Аппаратная платформа и тип компилятора прямо влияет на расположение битовых полей в структуре данных: в зависимости от реализации компилятора расположение битовых полей может начинаться с младших или старших битов. [Источник 2]
Объявление битовых полей
Элементом структуры может быть битовое поле, обеспечивающее доступ к отдельным битам памяти. Вне структур или объединений битовые поля объявлять нельзя. Нельзя также организовывать массивы битовых полей и нельзя применять к полям операцию определения адреса или получить ссылку на них.
Синтаксис объявления типа структуры с битовыми полями:
где struct – спецификатор типа;
Битовые поля длиной 1 должны объявляться как unsigned, поскольку 1 бит не может иметь знака. Битовые поля могут иметь длину от 1 до 16 бит для 16-битных сред и от 1 до 32 бит для 32-битных сред.
Разрешается поле без имени (для этого надо указать только двоеточие и ширину), с помощью которого в структуру вводятся неиспользуемые биты (промежуток между значимыми полями). Нулевая ширина поля вводится, когда необходимо, чтобы следующее в данной структуре поле разместилось с начала очередного машинного слова.
Например, если нам нужны только биты cts и dsr, то можно объявить структуру status_type следующим образом:
Регистр состояния процессора
Простой пример регистра состояния битового поля включен в конструкцию восьмибитового процессора 6502. В одном восьмибитовом поле хранилось семь фрагментов информации: Bit 7. Навигационный флаг Bit 6. Флаг переполнения Bit 5. Неиспользованный Bit 4. флаг перерыва Bit 3. десятичный флаг Bit 2. флаг применения-отключения Bit 1. флаг переноса Bit 0. Нулевой флаг
Unix код выхода процесса
Другим примером может служить системы Unix статус выхода код, который может быть использован в качестве флага для передачи информации о состоянии в другой процесс. Например, программа, которая контролирует состояние восьми переключателей охранной сигнализации может установить биты в код выхода, проходя по другому обрабатывая информацию о том, какие выключатели закрытые или открытые.
Изменение битов в словах флагов
Битовые поля
В противоположность другим компьютерным языкам С имеет возможность, называемую битовыми полями, позволяющую работать с отдельными битами. Битовые поля полезны по нескольким причинам. Ниже приведены три из них:
Хотя все эти функции могут выполняться с помощью битовых операторов, битовые поля могут внести большую ясность в программу.
struct имя структуры <
тип имя1: длина;
тип имя2: длина;
.
тип имяN: длина;
>
Битовые поля должны объявляться как int, unsigned или signed. Битовые поля длиной 1 должны объявляться как unsigned, поскольку 1 бит не может иметь знака. Битовые поля могут иметь длину от 1 до16 бит для 16-битных сред и от 1 до 32 бит для 32-битных сред. В Borland С++ самый левый бит является знаковым.
Рассмотрим приведенное ниже определение структуры:
struct device <
unsigned active : 1;
unsigned ready : 1;
unsigned xmt_error : 1;
> dev_code;
Данная структура определяет три переменные по одному биту каждая. Структурная переменная dev_code может, например, использоваться для декодирования информации из порта ленточного накопителя. Для такого гипотетического ленточного накопителя следующий фрагмент кода записывает байт информации на ленту и проверяет на ошибки, используя dev_code:
void wr_tape(char с)
<
while(!dev_code.ready) rd(&dev_code); /* ждать */
wr_to__tape (с); /* запись байта */
while(dev_code.active) rd(&dev_code); /* ожидание окончания записи информации */
if(dev_code.xmt error) printf(«Write Error»);
>
Здесь rd() возвращает статус ленточного накопителя wr_to_tape(), записывает данные. Рисунок показывает, как выглядит переменная dev_code в памяти.
Нет необходимости обзывать каждое битовое поле. К полю, имеющему название, легче получить доступ. Например, если ленточный накопитель возвращает информацию, о наступлении конца ленты в пятом бите, следует изменить структуру device следующим образом:
struct device <
unsigned active : 1;
unsigned ready : 1;
unsigned xmt_error : 1;
unsigned : 2;
unsigned EOT : 1;
> dev_code;
Битовые поля имеют некоторые ограничения. Нельзя получить адрес переменной битового поля. Переменные битового поля не могут помещаться в массив. Переходя с компьютера на компьютер нельзя быть уверенным в порядке изменения битов (слева направо или справа налево). Любой код, использующий битовые поля, зависит от компьютера.
Наконец, можно смешивать различные структурные переменные в битовых полях. Например:
struct emp <
struct addr address;
float pay;
unsigned lay_off:1;
unsigned hourly:1;
unsigned deductions:3;
>;