В языке С++ есть возможность задавать элементам структур определённое количество памяти в битах. Например, если необходимо создать структуру данных, соответствующую размеру регистра в каком-либо устройстве. Типом элемента (его называют битовым полем) такой структуры может быть целочисленное (чаще всего типа 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 байт в мингв мсвц и гцц и смаке
Тут некоторого очень важного уточнения
Использование такого механизма замедляет программу
Это связанно с тем, что будет сгенерирован код компилятором для манипуляций с данными(это будут побитовые операции), всё зависит от реализации компилятора(проверяйте его работу в .obj файле(если не знаете о том, что это, то смотрите как компилируется прога))
В нынешнее время – это может быть не значительным приростом времени, но если частота использования таких данных зашкаливает, то мы получим, возможно, крутую прогу, что требует мало ОЗУ, но точно медленную прогу
Так что пользуйтесь аккуратней и взвешивайте свое решение
Сергей, учусь я Вас, плачу деньги не Вам. Дам рекомендацию Вам, чтобы Вы учили. Вы хороший учитель. уважение к Вам полное