C++. Бархатный путь. Часть 2 - Битовые поля

ОГЛАВЛЕНИЕ

 

Битовые поля

Битовое поле - это последовательность битов. Минимальная длина битового поля, естественно, равняется 1 (одному биту), максимальная длина зависит от реализации. Битовое поле длинной в восемь бит - не байт. Байт - это минимальная адресуемая область памяти ЭВМ, битовое поле - языковая конструкция. Среди форм Бэкуса-Наура, посвящённых объявлению класса, напомним соответствующую БНФ:

ОписательЧленаКласса ::= [Идентификатор] : КонстантноеВыражение

Вот такой описатель члена класса и задаёт битовое поле. Битовое поле может существовать исключительно как элемент класса. Идентификатор (необязательный!) задаёт имя поля, константное выражение - размеры этого поля в битах. Согласно ранее приведённым БНФ, подобному описателю должны предшествовать спецификаторы объявления. Как известно, они специфицируют тип объявляемого члена класса.

В C++ существует ограничения на тип битового поля. Это всегда целочисленный тип. Вполне возможно, что тип знаковый. По крайней мере, в Borland C++, максимально допустимый размер поля равняется длине (количеству бит), объекта соответствующего типа.

Рассмотрим пример объявления битового поля:

ОбъявлениеЧленаКласса ::= [СписокСпецификаторовОбъявления] [СписокОписателейЧленовКласса]; ::= СпецификаторОбъявления ОписательЧленаКласса; ::= int [Идентификатор] : КонстантноеВыражение; ::= int MyField:5; А вот как объявления битовых полей выглядят в контексте объявления класса: struct BitsFields { int IntField : 1; char CharField : 3; int : 3 unsigned UnsignedField : 1; };

Неименованное битовое поле также является членом класса. Существует множество ситуаций, в которых оправдано использование неименованных битовых полей. В конце концов, они ничем не хуже неименованных параметров функций. Неименованные поля могут использоваться для заполнения соответствующей области памяти. Если это поле является полем нулевой длины (для неименованного поля возможно и такое), оно может задавать выравнивание следующего битового поля по границе очередного элемента памяти. Хотя и здесь, в конечном счёте, многое зависит от реализации.

К неименованным битовым полям нельзя обратиться по имени, их невозможно инициализировать и также невозможно прочитать их значение путём непосредственного обращения к битовому полю.

Именованные битовые поля инициализируются подобно обычным переменным. И значения им можно присвоить любые (разумеется, в пределах допустимого для данного типа диапазона значений).

BitsFields QWE; ::::: QWE.CharField = 100; QWE.IntField = 101; QWE.UnsignedField = 1;

Но фактически значения в битовом поле ограничиваются размерами битового поля. Было поле объявлено размером в три бита - диапазон его значений и будет ограничен этими самыми тремя битами:

cout << QWE.CharField << "....." << endl; cout << QWE.IntField << "....." << endl; cout << QWE.UnsignedField << "....." << endl; :::::

В Borland C++ у битового поля знакового типа, независимо от размеров этого поля, один из битов остаётся знаковым. В результате, однобитовое знаковое поле способно принимать только одно из двух значений: либо -1, либо 0.

В ряде книг утверждается, что битовые поля способствуют "рациональному использованию памяти". В "Справочном руководстве по C++" на этот счёт высказывается мнение, что подобные усилия "наивны и вместо цели (экономии памяти) могут привести к лишним тратам памяти". Даже если в конкретной реализации и удастся упаковать несколько маленьких элементов в одно слово, то извлечение значения битового поля может потребовать дополнительных машинных команд.

Здесь экономия "по мелочам" на деле может обернуться большими потерями. Однако, если битовые поля существуют, значит, кому-то могут быть необходимы или, по крайней мере, удобны.