Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lek9_cpp_ukr.rtf
Скачиваний:
1
Добавлен:
18.11.2019
Размер:
998.94 Кб
Скачать

1.3. Бітові поля

       Бітові поля (bit fields) - особливий вид полів структури. Вони дають можливість задавати кількість бітів, в яких зберігаються елементи цілих типів. Бітові поля дозволяють раціонально використовувати пам'ять за допомогою зберігання даних в мінімально потрібній кількості бітів.

       При оголошенні бітового поля вслід за типом елемента ставиться двокрапка (:) і вказується цілочисельна константа, яка задає розмір поля (кількість бітів). Розмір поля повинен бути константою в діапазоні між 0 і заданим загальним числом бітів, яке використовується для зберігання даного типу даних.

struct bit_field {        int bit_1 : 1;        int bits_2_to_5 : 4;        int bit_6 : 1;        int bits_7_to_16 : 10; } bit_var;

2. Об'єднання (union)

        Об'єднання дозволяють в різні моменти часу зберігати в одному об'єкті значення різного типу. В процесі оголошення об'єднання з ним асоціюється набір типів, які можуть зберігатися в даному об'єднанні. В кожний момент часу об'єднання може зберігати значення тільки одного типу з набору. Контроль за тим, значення якого типу зберігається в даний момент в об'єднанні покладається на програміста.

Синтаксис :

union [ім'я_об'єднання]  {         тип1 елемент1;         тип2 елемент2;         ........................         типN елементN; } [список описів];

        Пам'ять, яка виділяється під змінну типу об'єднання, визначається розміром найбільш довгого з елементів об'єднання. Всі елементи об'єднання розміщуються в одній і тій же області пам'яті з однієї й тієї ж адреси. Значення поточного елемента об'єднання втрачається, коли іншому елементу об'єднання присвоюється значення.

Приклад 1:

union sign {     int svar;     unsigned uvar; } number;

Приклад 2 :

union  {     char *a,b;     float f[20]; } var;

        В першому прикладі оголошується змінна типу об'єднання з ім'ям number. Список оголошень елементів об'єднання містить дві змінні : svar типу int і uvar типу unsigned. Це об'єднання дозволяє запам'ятати ціле значення в знаковому або в без знаковому вигляді. Тип об'єднання має ім'я sign.

        В другому прикладі оголошується змінна типу об'єднання з ім'ям var. Список оголошень елементів містить три оголошення : покажчика a на значення типу char, змінної b типу char і масиву f з 20 елементів типу float. Тип об'єднання не має імені. Пам'ять, що виділяється під змінну var, рівна пам'яті, необхідної для зберігання масиву f, так як це найдовший елемент об'єднання.

Битовые поля

При дефиците памяти может возникнуть необходимость запаковать несколько объектов в одно слово машины. Одна из обычных ситуаций, встречающаяся в задачах обработки таблиц символов для компиляторов, — это объединение групп однобитовых флажков. Форматы некоторых данных могут от нас вообще не зависеть и диктоваться, например, интерфейсами с аппаратурой внешних устройств; здесь также возникает потребность адресоваться к частям слова.

Вообразим себе фрагмент компилятора, который заведует таблицей символов. Каждый идентификатор программы имеет некоторую связанную с ним информацию: например, представляет ли он собой ключевое слово или, если это переменная, к какому классу принадлежит: внешняя, статическая и т.д. Самый компактный способ кодирования такой информации — расположить однобитовые флажки в одном слове типа char или int.

Один из распространенных приемов работы с битами основан на определении набора «масок», соответствующих позициям этих битов, например:

#define KEYWORD 01 /* ключевое слово */

#define EXTERNAL 02 /* внешний объект */

#define STATIC 04 /* статический объект */

или

enum { KEYWORD = 01, EXTERNAL = 02, STATIC = 04 };

Числа должны быть степенями двойки. Тогда доступ к битам становится делом порязрядных операций (сдвиг, маскирование, инвертирование).

Некоторые виды записи выражений встречаются довольно часто. Так

flags |= EXTERNAL | STATIC;

устанавливает 1 в соответствующих битах переменной flags,

flags &= ~(EXTERNAL | STATIC);

обнуляет их, а

if ((flags & (EXTERNAL | STATIC)) == 0) ...

оценивает условие как истинное, если оба бита нулевые.

Хотя научиться писать такого рода выражения не составляет труда, вместо поразрядных логических операций можно пользоваться предоставляемым Си другим способом прямого определения и доступа к полям внутри слова. Битовое поле (или для краткости просто поле) — это некоторое множество битов,лежащих рядом внутри одной, зависящей от реализации единицы памяти, которую мы будем называть «словом». Синтаксис определения полей и доступа к ним базируется на синтаксисе структур. Например, строки #define, фигурировавшие выше при задании таблицы символов, можно заменить на определение трех полей:

struct {

unsigned int is_keyword : 1;

unsigned int is_extern : 1;

unsigned int is_static : 1;

} flags;

Эта запись определяет переменную flags, которая содержит три однобитовых поля. Число, следующее за двоеточием, задает ширину поля. Поля объявлены как unsigned int, чтобы они воспринимались как беззнаковые величины.

На отдельные поля ссылаются так же, как и на элементы обычных структур: flags.is_keyword, flags.is_extern и т.д. Поля могут участвовать в арифметических выражениях точно так же, как и другие целые числа. Таким образом, предыдущие примеры можно написать более естественно:

flags.is_extern = flags.is_static = 1;

устанавливает 1 в соответствующих битах;

flags.is_extern = flags.is_static = 0;

их обнуляет, а

if (flags.is_extern == 0 && flags.is_static == 0)

...

проверяет их.

Почти все технические детали, касающиеся полей, в частности, возможность поля перейти границу слова, зависят от реализации. Поля могут не иметь имени; с помощью безымянного поля (задаваемого только двоеточием и шириной) организуется пропуск нужного количества разрядов. Особая ширина, равная нулю, используется, когда требуется выйти на границу следующего слова.

На одних машинах поля размещаются слева направо, на других — справа налево. Это значит, что при всей полезности работы с ними, если формат данных, с которыми мы имеем дело, дан нам свыше, то необходимо самым тщательным образом исследовать порядок расположения полей. Программы, зависящие от такого рода вещей, не переносимы. Поля можно определять только с типом int, а для того, чтобы обеспечить переносимость, надо явно указывать signed или unsigned. Они не могут быть массивами и не имеют адресов, и, следовательно, операция & к ним не применима.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]