Бітові поля в структурах. Приклади
Зміст
- 1. Бітові поля. Загальні поняття. Синтаксис
- 2. Приклад використання бітових полів у структурі Date, що описує дату дня та номер дня в тижні
- 3. Приклад порівняння структури з бітовими полями зі структурою, що не використовує бітових полів. Структура Time
- Споріднені теми
Пошук на інших ресурсах:
1. Бітові поля. Загальні поняття. Синтаксис
Структури дозволяють зручно групувати дані (змінні) за деяким критерієм. В пам’яті такі дані, як правило, розміщуються один за одним згідно оголошення.
У мові C++ існує засіб стиснення розміру пам’яті, що виділяється під оголошені в структурі змінні. Це бітові поля у структурах.
Бітові поля використовуються для зберіганні даних цілих типів. При використанні бітових полів у розмірі типу для них виділяється строго визначена кількість біт.
Бувають випадки, коли для збереження даних розмір пам’яті, що для них виділився, є надто великим.
Наприклад, щоб зберігати дані про день тижня, розміру 1 байту або 8 біт є забагато. Існує 7 днів тижня, тому достатньо 3 біт для представлення цих даних (2 у степені 3 = 8 значень).
Оголошення бітового поля у структурі виглядає наступним чином
unsigned int field : value;
тут
- field – ім’я поля (змінної) в структурі;
- value – кількість біт, які виділяються для представлення множини значень бітового поля.
В свою чергу, оголошення структури, що містить бітові поля має приблизно такий вигляд:
struct StructName { unsigned int field_1 : value_1; unsigned int field_2 : value_2; ... unsigned int field_N : value_N };
тут
- StructName – ім’я структури;
- field_1, field_2, field_N – назви змінних, що віповідають бітовим полям структури;
- value_1, value_2, value_N – цілочисельні значення, що є кількістю виділених біт під розміри відповідно полів field_1, field_2, field_N.
В якості бітових полів рекомендовано використовувати тип unsigned int. Це не спотворить результат, якщо перший біт буде встановлено в 1 що буде означати від’ємне число. Однак, при використанні інших цілочисельних типів компілятор не буде видавати помилки.
Якщо в структурі оголосити тільки одне бітове поле, то це не дасть ніякого ефекту. Дані в пам’яті все одно будуть зберігатись у вигляді, що кратний 8 бітам або 1 байту (вирівнювання). Користь від бітових полів зростає, якщо в структурі зберігається велика кількість цілочисельних даних. При великій кількості бітових полів, можна зекономити значну кількість байт під один і той самий набір даних без їх втрати. У свою чергу, використання масивів структур з бітовими полями, дозволяє суттєво зменшити розмір збережуваних даних та пришвидшити виконання команд обробки цих даних.
⇑
2. Приклад використання бітових полів у структурі Date, що описує дату дня та номер дня в тижні
У задачі оголошується структура Day, яка описує такі дані про день:
- номер дня в тижі від 1 до 7. Тут 1 це понеділок, 2 – вівторок і т.д., 7 – неділя;
- число в місяці – 1..31;
- номер місяця – 1..12;
- рік. Діапазон від 0 до 3000 року.
Для представлення дня тижня достатньо 3 біт, оскільки 3 біти дозволяють отримати 8 значень (2^3 = 8). Тобто, 8 значень покривають 7 значень, які потрібно для збереження номеру дня тижня.
Виходячи з вищенаведених міркувань про день тижня, можна сформувати кількість біт для інших полів структури Day:
- число в місяці достатньо представити 5 бітами (2^5 = 32, 32>31);
- номер місяця достатньо представити 4 бітами (2^4 = 16, 16>12);
- на збереження року достатньо 12 біт (2^12 = 4096, 4096>3000).
Текст демонстраційної програми наступний
#include <iostream> using namespace std; struct Day { unsigned int weekDay : 3; // день тижня 1..7 unsigned int number : 5; // число 1..31 unsigned int month : 4; // номер місяця 1..12 unsigned int year : 12; // рік 0..3000 }; void main() { // Поля бітів у структурах // 1. Оголосити структуру Day d; // 2. Заповнити структуру даними 14.01.2022, п'ятниця d.weekDay = 5; d.number = 14; d.month = 1; d.year = 2022; // 3. Вивести дані cout << "d.weekDay = " << d.weekDay << endl; cout << "d.number = " << d.number << endl; cout << "d.month = " << d.month << endl; cout << "d.year = " << d.year << endl; // 4. Вивести розмір структури cout << "sizeof(Day) = " << sizeof(d) << endl; // 4 байти }
Результат виконання програми
d.weekDay = 5 d.number = 14 d.month = 1 d.year = 2022 sizeof(Day) = 4
⇑
3. Приклад порівняння структури з бітовими полями зі структурою, що не використовує бітових полів. Структура Time
Нехай потрібно реалізувати структуру Time, яка описує часовий інтервал у вигляді
hours : minutes : seconds : milliseconds
тут
- hours – кількість годин у добі 0..23;
- minutes – кількість хвилин у годині 0..59;
- seconds – кількість секунд у хвилині 0..59;
- milliseconds – кількість мілісекунд 0..999.
Найкраще для опису подібних даних в структурі використовуються поля бітів. Виходячи з максимально-допустимих значень, для різних часових інтервалів можна виділити різну кількість біт в їх представленні у структурах:
- поле hours – 5 біт (2^5 = 32 > 23). З 5 бітів можна сформувати до 2^5=32 різних значень, що цілком достатньо для представлення 24 значень цього поля;
- minutes – 6 біт (2^6 = 64 > 59);
- seconds – 6 біт (2^6 = 64 > 59);
- milliseconds – 10 біт (2^10 = 1024 > 999).
У програмі, з метою демонстрації, створюється дві структури Time та Time2, в яких реалізовані необхідні поля для представлення часу. Однак, структура Time використовує бітові поля, а структура Time2 використовує звичайні значення типу unsigned int.
Текст програми наступний
#include <iostream> using namespace std; // Структура Time використовує бітові поля struct Time { unsigned int hours : 5; unsigned int minutes : 6; unsigned int seconds : 6; unsigned int milliseconds : 10; }; // Структура Time2 не використовує бітові поля struct Time2 { unsigned int hours; unsigned int minutes; unsigned int seconds; unsigned int milliseconds; }; void main() { // Порівняння структур з бітовими полями та без них // 1. Оголосити змінні Time tm; Time2 tm2; // 2. Використання структур у програмі // 2.1. Структура типу Time tm.hours = 12; tm.seconds = 36; tm.milliseconds = 777; tm.minutes = 3; // 2.2. Структура типу Time2 tm2.hours = 20; tm2.seconds = 39; tm2.milliseconds = 555; tm2.minutes = 55; // 3. Визначити та вивести розмір структур Time, Time2 // з допомогою оператора sizeof() size_t sizeTime = sizeof(Time); // 4 size_t sizeTime2 = sizeof(Time2); // 16 cout << "sizeTime = " << sizeTime << endl; cout << "sizeTime2 = " << sizeTime2 << endl; }
Результат виконання програми
sizeTime = 4 sizeTime2 = 16
Як видно з результату, відмінностей між використанням звичайних структур та бітових структур немає (доступ до полів, заповнення даними тощо). Однак, розмір бітової структури (змінна tm) в пам’яті займає всього-навсього 4 байти порівняно з розміром звичайної структури в 16 байт.
У структурі Time відбувається додавання бітів у полях. Сумарна кількість бітів становить
5 + 6 + 6 + 10 = 27
Якщо розділити 27 на 8 (кількість біт у байті), то вийде 3 з надлишком. Тобто, для представлення 27 біт потрібно 4 байти щоб коректно відобразити дані.
⇑
Споріднені теми
- Складені типи даних. Шаблон структури. Структурна змінна. Структури в середовищі CLR. Оголошення та ініціалізація структурної змінної
- Об’єднання. Ключове слово union. Приклади використання об’єднань
⇑