В языке С++ есть возможность задавать элементам структур определённое количество памяти в битах. Например, если необходимо создать структуру данных, соответствующую размеру регистра в каком-либо устройстве. Типом элемента (его называют битовым полем) такой структуры может быть целочисленное (чаще всего типа unsigned) или перечислимое (enum).
Синтаксически битовое поле в структуре определяется следующим образом:
Например:
1 2 3 4 5 6 | struct fieldbite { unsigned short first : 2; unsigned short second: 2; unsigned short third : 4; } field; |
Мы определили структуру, в которой переменные будут занимать указанное количество бит. 2 + 2 + 4 дает 8 бит (мы выровняли до размера байта). Если в эту структуру дописать еще unsigned short fifth : 5; – уже будет задействовано 2 байта. Во втором байте естественно будет мусор 8 – 5 = 3 бита, которые будут невостребованными.
В отличии от объединений (union) размер битовых полей варьируется, в зависимости от того, сколько бит программист заказал. Если заказано 7 бит (скажем две переменные по 3 бита, и одна – 1 бит), то С++ отведет один байт (8 бит) под эти три переменные.
Если программист закажет 11 бит, то С++ отведет два байта (16 бит). Причем во втором байте будут задействованы только 5 бит, а остальные скорее всего будут, как бесполезный хвост. Поэтому при описании битовых полей следует учитывать такое “выравнивание” до байта. Т.е. распределять в нем переменные так, чтоб каждый бит был востребован. Для выравнивания занимаемой памяти можно использовать неименованные битовые поля.
Приведем еще один короткий пример, в котором битовые поля отводятся под дату и время для демонстрации этой технологии.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <iostream> using namespace std; struct DateTime //Опишем структуру с битовыми полями { unsigned short Day : 5; //5 бит для дня unsigned short Month : 4; //4 для месяца unsigned short Year : 7; //7 для года от 0 до 99 unsigned short Hour : 5; //5 бит для 24-х часов unsigned short Minute : 6;//6 для минут unsigned short Second : 6;//6 для секунд }; int main() { DateTime d; //объявляем переменную этого типа с битовыми полями int i; //И еще одну, в которую будет поступать ввод данных //Введем дату cout << "Input day (1-31):" << '\t'; cin >> i; d.Day = i; cout << "Input month (1-12):" << '\t'; cin >> i; d.Month = i; cout << "Input Year (00-99) :" << '\t'; cin >> i; d.Year = i; //Введем время cout << endl << "Input Hour (0-24):" << '\t'; cin >> i; d.Hour = i; cout << "Input Minute (0-60):" << '\t'; cin >> i; d.Minute = i; cout << "Input Seconds (0-60):" << '\t'; cin >> i; d.Second = i; //И выведем их с показателем размера в памяти cout << endl << "Date is: " << d.Day << "." << d.Month << ".20" << d.Year << " "; cout << d.Hour << ":" << d.Minute << ":" << d.Second << endl; cout << sizeof(d) << endl; } |
Результат:
Как видите, битовые поля хранят дату и время. Занимает эта структура 6 байт, хотя для неё хватит и пяти. И на то есть свои причины: сам компилятор может выравнивать отводимую память до четного числа байтов.
Например если мы заказали 18 бит, компилятор отведет нам не 3 байта, а 4, учитывая что процессор любит работать с байтами, а не с битами. По крайней мере хранить в памяти или своих регистрах процессор предпочитает не биты, а именно байты. Согласно его разрядности: x32 хранят 4 байта, x64 уже 8 байт. Пусть даже из этих байт работа идет только с одним из них, остальные все равно будут подтягиваться.
Небольшой итог: Битовые поля в структурах обычно используются в низкоуровневом программировании, когда работа идет со значениями, способными занимать не байты, а отдельные биты (ввиду того, что значения небольшие).
Дезинформируете людей. Размер
{
unsigned short first : 2;
unsigned short second: 2;
unsigned short third : 4;
} равен не 1 байту, а 2
2+2+4 = 8бит, 8бит = 1 байту Привет, я у мамки программист?))
Нет, он всё верно сказал, 2 байта.
Если поставить unsigned char, то один байт, но вот сейчас два. Поверь в любой ide.
А если int, то 4; и аналогично для восмибайтовых.
struct test{
unsigned long long first : 64;
unsigned char second: 8;
}; – имеет размер в 16 байт вместо ожидаемых тобой 9.
Он выравнивает по размеру типа максимального размера, по видимому.
Align
try
#pragma pack(push,1)
typedef struct{
unsigned short first :2;
unsigned short second:2;
unsigned short third :4;
} foo;
#pragma pop()
Хотя и так 1 байт в мингв мсвц и гцц и смаке