Последнее обновление:2026-10-12
C++ битовые поля¶
Об авторе:¶
Личный официальный аккаунт:

Что такое Bit field?¶
Битовое поле (Bit field) — это структура данных, позволяющая компактно хранить данные в виде битов и дающая программисту возможность оперировать битами этой структуры. Преимущество такой структуры данных в том, что она позволяет экономить место при хранении элементов данных, и когда программе требуются тысячи таких элементов, этот подход становится особенно важным. Второе преимущество — битовые поля позволяют удобно обращаться к отдельным частям целочисленного значения, что упрощает исходный код программы. Недостаток же этой структуры данных в том, что реализация битовых полей зависит от конкретной машины и системы, на разных платформах результаты могут различаться, из-за чего битовые поля по своей сути непереносимы.
- Размещение битового поля в памяти зависит от машины
- Тип битового поля должен быть целочисленным или перечислением; поведение битовых полей в знаковых типах зависит от конкретной реализации
- Оператор взятия адреса (&) неприменим к битовому полю; никакой указатель не может указывать на битовое поле класса
Использование битовых полей¶
Битовые поля обычно объявляются с помощью структуры; в таком объявлении каждому члену-битовому полю задаётся имя и определяется его ширина:
| Elements | Description |
|---|---|
| bit_field_name | имя структуры битового поля |
| type | тип члена битового поля; должен быть int, signed int или unsigned int |
| member_name | имя члена битового поля |
| width | количество бит, занимаемых членом |
Например, объявим следующее битовое поле:
struct _PRCODE
{
unsigned int code1: 2;
unsigned int cdde2: 2;
unsigned int code3: 8;
};
struct _PRCODE prcode;
Это определение делает prcode содержащим 2 двухбитовых поля и 1 восьмибитовое поле; мы можем присваивать им значения с помощью оператора доступа к членам структуры
При присваивании следует следить, чтобы значение не превышало ёмкость члена битового поля: например, prcode.code3 — восьмибитовый член битового поля, его ёмкость составляет 2^8 = 256, то есть диапазон присваиваемых значений должен быть [0,255].
Размер и выравнивание битового поля¶
Размер битового поля¶
Например, следующее битовое поле:
В середине этой структуры битового поля есть безымянное битовое поле, занимающее 3 бита; оно служит только заполнителем и не имеет практического смысла. Заполнитель делает так, что структура в целом использует 8 бит. Однако в языке C базовой единицей битового поля является unsigned int, поэтому даже если единственный член структуры — однобитовое поле, размер структуры будет таким же, как у unsigned int. В некоторых системах unsigned int занимает 16 бит, в системах x86 — 32 бита. Далее в статье по умолчанию считается, что unsigned int занимает 32 бита.
Выравнивание битового поля¶
Член битового поля не может пересекать границу двух unsigned int; если общее число бит, объявленных для членов, превышает размер одного unsigned int, компилятор автоматически сдвигает члены битового поля так, чтобы они были выровнены по границе unsigned int. Например:
field1 + field2 = 34 бита, что превышает 32 бита; компилятор переместит field2 в следующий unsigned int-блок, между stuff.field1 и stuff.field2 останется зазор в 2 бита, stuff.field3 идёт сразу после stuff.field2, и теперь размер структуры составляет 2 * 32 = 64 бита.
Эта «пустота» может быть заполнена упомянутым ранее безымянным членом битового поля; кроме того, можно использовать безымянный член битового поля нулевой ширины, чтобы следующий член битового поля был выровнен по следующему целому числу. Например:
struct stuff
{
unsigned int field1: 30;
unsigned int : 2;
unsigned int field2: 4;
unsigned int : 0;
unsigned int field3: 3;
};
Здесь между stuff.field1 и stuff.field2 есть зазор в 2 бита, stuff.field3 же хранится в следующем unsigned int, и теперь размер структуры составляет 3 * 32 = 96 бит.
Учебный код см. в: bit.cpp
Инициализация битовых полей и переназначение битов¶
Инициализация¶
Инициализация битового поля выполняется так же, как инициализация обычной структуры; приведём два способа:
либо можно напрямую присвоить значения членам битового поля
Переназначение битового поля (Re-mapping)¶
Объявим битовое поле размером 32 бита
struct box {
unsigned int ready: 2;
unsigned int error: 2;
unsigned int command: 4;
unsigned int sector_no: 24;
}b1;
Обнуление битового поля с помощью переназначения¶
Переназначение 32-битового поля в unsigned int с помощью объединения (union)¶
Сначала кратко расскажем об объединении
«Объединение» — это особый класс, а также составной тип структуры данных. Внутри «объединения» можно определять различные типы данных; в переменную, объявленную как тип этого «объединения», допускается поместить любой из типов данных, определённых в «объединении»; эти данные используют одну и ту же память, чтобы экономить место
У «объединения» и «структуры» есть некоторое сходство, но между ними есть и принципиальная разница. В структуре каждый член имеет собственное пространство памяти, а общая длина структурной переменной равна сумме длин всех членов (кроме пустых структур и без учёта выравнивания границ). В «объединении» же все члены используют одно пространство памяти, а длина переменной объединения равна длине самого длинного из членов. Следует пояснить: под общим использованием здесь не понимается одновременное размещение нескольких членов в одной переменной объединения — имеется в виду, что переменной объединения может быть присвоено значение любого члена, но каждый раз только одно; присваивание нового значения стирает старое.
Мы можем объявить следующее объединение:
В системах x86 и unsigned int, и box занимают 32 бита; через это объединение st_box и ui_box используют одну область памяти. Какой именно бит битового поля соответствует какому биту unsigned int, зависит от компилятора и аппаратуры. Обнулим битовое поле с помощью объединения, код таков:
Материал подготовлен по: http://www.yuan-ji.me/C-C-%E4%BD%8D%E5%9F%9F-Bit-fields-%E5%AD%A6%E4%B9%A0%E5%BF%83%E5%BE%97/
Похожие темы¶
- C++ чисто виртуальные функции и абстрактные классы | C++那些事
- C++ утверждения assert | C++那些事
- Реализация полиморфизма C++ на языке C | C++那些事
- C++ константы const и его модификация | C++那些事
- C++ всё семейство const | C++那些事
- C++ оператор разыменования * | C++那些事
- C++ инициализация и присваивание | C++那些事
- C++ возврат нескольких значений | C++那些事
- C++ ключевое слово mutable | C++那些事
- C++ restrict и оптимизации компилятора | C++那些事