Поиск…
Вступление
Бит-поля плотно упаковывают структуры C и C ++ для уменьшения размера. Это кажется безболезненным: укажите количество бит для членов, а компилятор выполняет работу со-смешивающих битов. Ограничением является невозможность принять адрес члена битового поля, поскольку он хранится совместно. sizeof()
также не разрешено.
Стоимость битных полей - это более медленный доступ, так как память должна быть восстановлена и побитовые операции применяются для извлечения или изменения значений элементов. Эти операции также добавляют к размеру исполняемого файла.
замечания
Насколько дороги побитовые операции? Предположим, что простая небитовая структура поля:
struct foo {
unsigned x;
unsigned y;
}
static struct foo my_var;
В более позднем коде:
my_var.y = 5;
Если sizeof (unsigned) == 4
, то x сохраняется в начале структуры, а y хранится в 4 байта. Сгенерированный код сборки может напоминать:
loada register1,#myvar ; get the address of the structure
storei register1[4],#0x05 ; put the value '5' at offset 4, e.g., set y=5
Это просто, потому что х не смешивается с y. Но представьте себе переопределение структуры с битовыми полями:
struct foo {
unsigned x : 4; /* Range 0-0x0f, or 0 through 15 */
unsigned y : 4;
}
И x
и y
будут выделены 4 бита, разделяя один байт. Таким образом, структура занимает 1 байт, а не 8. Рассмотрим сборку, чтобы установить y
теперь, предполагая, что она заканчивается в верхнем полубайте:
loada register1,#myvar ; get the address of the structure
loadb register2,register1[0] ; get the byte from memory
andb register2,#0x0f ; zero out y in the byte, leaving x alone
orb register2,#0x50 ; put the 5 into the 'y' portion of the byte
stb register1[0],register2 ; put the modified byte back into memory
Это может быть хорошим компромиссом, если у нас есть тысячи или миллионы этих структур, и это помогает хранить память в кеше или препятствует обмену - или может раздуть исполняемый файл, чтобы ухудшить эти проблемы и медленную обработку. Как и все, используйте здравый смысл.
Использование драйвера устройства: избегайте бит-полей как умной стратегии реализации драйверов устройств. Битовые поля хранения не обязательно согласованы между компиляторами, что делает такие реализации не переносимыми. Значение read-modify-write для установки значений может не делать то, что ожидают устройства, вызывая неожиданное поведение.
Декларация и использование
struct FileAttributes
{
unsigned int ReadOnly: 1;
unsigned int Hidden: 1;
};
Здесь каждое из этих двух полей будет занимать 1 бит в памяти. Он определяется выражением : 1
после имен переменных. Базовый тип битового поля может быть любым интегральным типом (8-битный int до 64-битного int). Рекомендуется использовать unsigned
тип, иначе могут возникнуть сюрпризы.
Если требуется больше бит, замените «1» на количество бит. Например:
struct Date
{
unsigned int Year : 13; // 2^13 = 8192, enough for "year" representation for long time
unsigned int Month: 4; // 2^4 = 16, enough to represent 1-12 month values.
unsigned int Day: 5; // 32
};
Вся структура использует всего 22 бита, и с обычными настройками компилятора sizeof
этой структуры будет 4 байта.
Использование довольно простое. Просто объявите переменную и используйте ее как обычную структуру.
Date d;
d.Year = 2016;
d.Month = 7;
d.Day = 22;
std::cout << "Year:" << d.Year << std::endl <<
"Month:" << d.Month << std::endl <<
"Day:" << d.Day << std::endl;