Об’єднання. Ключове слово union. Приклади використання об’єднань

Об’єднання. Ключове слово union. Приклади використання об’єднань


Зміст



1. Що таке об’єднання в мові C++? Для чого використовуються об’єднання?

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

Об’єднання дозволяє представити дані, що змінюються в компактному вигляді. Одні й ті ж дані можуть бути представлені різними способами з допомогою об’єднань.

Так як і структури, об’єднання вимагають оголошення типу (шаблону) та оголошення змінної цього типу.

2. Як виглядає загальна форма оголошення типу (шаблону) об’єднання? Ключове слово union

Оголошення об’єднання (типу об’єднання або шаблону об’єднання) починається з ключового слова union.

union ім’я_типу_об’єднання
{
    тип змінна1;
    тип змінна2;
    ...
    тип зміннаN;
};

де

  • ім’я_типу_об’єднання – безпосередньо ім’я новостворюваного типу;
  • змінна1, змінна2, зміннаN – змінні, що є полями об’єднання. Ці змінні можуть бути різних типів;
  • тип – тип змінної, що є полем об’єднання.

Тип змінної може бути:

3. Що таке довжина об’єднання? Як обчислюється довжина об’єднання?

Довжина об’єднання – це розмір пам’яті в байтах, що виділяється для однієї змінної цього типу об’єднання.

Довжина об’єднання обчислюється як максимум з усіх довжин (розмірів у байтах) окремих полів шаблону. Слід нагадати, що одне поле – це оголошення однієї змінної в об’єднанні (див. п. 2).

4. Як оголосити тип (шаблон) об’єднання та змінну цього типу? Приклад

Нехай задано тип об’єднання, що містить змінні типів з плаваючою точкою

// оголошення типу "об'єднання Floats"
union Floats
{
    float f; // розглядається 4 байти
    double d; // розглядається 8 байт
};

Тип об’єднання Floats містить 2 змінні з іменами f та d. Змінна f є типу float, змінна d є типу double. Для змінної f типу float розглядається (береться до уваги) 4 байти. Для змінної d типу double береться до уваги 8 байт, тому що компілятор виділяє для цього типу саме 8 байт.

Щоб використати об’єднання Floats в іншому програмному коді (методі, обробнику події тощо) потрібно оголосити змінну типу Floats як показано нижче

Floats Fl;
int d;
Fl.f = 20.5; // Fl.d не визначене
Fl.d = -100.35; // тепер Fl.f не визначене

d = sizeof(Fl); // d = 8

Оскільки розміщення змінних в пам’яті умовно починається з однієї адреси, то для змінної Fl типу Floats виділяється 8 байт пам’яті. Це зв’язано з тим, що змінна типу double вимагає більше пам’яті для свого представлення ніж змінна типу float.

На рисунку 1 відображено розміщення (інтерпретація) змінних f, d з об’єднання Floats.

C++ об'єднання представлення даних

Рис. 1. Представлення змінних f, d в об’єднанні Floats

5. Як здійснюється доступ до полів об’єднання?

Доступ до полів об’єднання здійснюється так само, як і для структури:

  • з допомогою символу .;
  • з допомогою послідовності символів ‘->’ у випадку, коли оголошено змінну-покажчик на об’єднання.

6. Приклад оголошення та використання покажчика на об’єднання

Робота об’єднань з некерованими (*) покажчиками є така сама, як і робота структур з некерованими покажчиками.

У нижченаведеному прикладі оголошується некерований покажчик на об’єднання типу Ints

Демонстрація використання некерованого покажчика (*) для об’єднання типу Ints

// покажчик на об'єднання
Ints *pI; // некерований покажчик

// виділити пам'ять для об'єднання
pI = new Ints;

// доступ до полів з допомогою покажчика
pI->a = 200;
pI->b = 3400;

7. Як оголосити вкладені об’єднання (структури, класи) в шаблоні об’єднання? Приклад

Шаблон об’єднання може включати поля, що є структурами, об’єднаннями та класами.

У прикладі нижче оголошується шаблон об’єднання з іменем Types, що містить два вкладені об’єднання Floats та Ints, структуру ArrayOfChars і клас MyPoint.

Оголошення структури та об’єднань має такий вигляд

// об'єднання цілочисельних типів
union Ints
{
    unsigned short int a;
    unsigned int b;
    unsigned long int c;
};

// структура, що містить 2 рядки
struct ArrayOfChars
{
    char A[10];
    char B[8];
};

// оголошення типу "об'єднання Floats"
union Floats
{
    float f; // розглядається 4 байти
    double d; // розглядається 8 байт
};

Оголошення шаблону класу має такий вигляд:

// клас оголошується в окремому модулі, наприклад MyPoint.h
#pragma once
class MyPoint
{
    public:
        int x;
        int y;

        // методи класу
        int GetX(void) { return x; }
        int GetY(void) { return y; }
        void SetXY(int nx, int ny) { x = nx; y = ny; }
};

Оголошення типу об’єднання Types з вкладеними складними типами Ints, Floats, ArrayOfChars, MyPoint.

// підключити модуль з оголошеним класом MyPoint
#include "MyPoint.h"

...

// оголошення типу "об'єднання Types"
union Types
{
    Floats Fl; // об'єднання
    Ints I;   // об'єднання
    ArrayOfChars A; // структура
    MyPoint MP;   // клас
};

Використання об’єднання Types в деякому програмному коді:

// оголосити змінну типу "об'єднання Types"
Types T;

// змінити значення полів змінної T
T.Fl.f = (float)20.35; // об'єднання Floats
T.I.b = 230; // об'єднання Ints
T.A.A[2] = 'A'; // структура ArrayOfChars
T.MP.SetXY(3,8); // клас MyPoint
int d;
d = T.MP.GetX(); // d = 3

8. Як описати масив об’єднань? Приклад
// Приклад оголошення та використання масиву об'єднань
Floats F[5]; // оголошується масив з 5 об'єднань типу Floats

// заповнення значень полів
for (int i=0; i<5; i++)
{
    F[i].d = i*0.2 + i*i;
}

9. Які особливості застосування операції sizeof() для об’єднань та структур?

У програмах на C++ для визначення розміру змінної типу “структура” або “об’єднання” обов’язково потрібно використовувати операцію sizeof. Визначення розміру “вручну” є помилковим тому що:

  • розміри деяких вбудованих типів (наприклад тип int) можуть бути різними для різних комп’ютерів. Наприклад, на одних платформах для типу int буде виділено 2 байти, на інших 4 байти;
  • компілятор робить так зване “вирівнювання пам’яті” на межі слова (2 байти) або абзацу (16 байт). Наприклад, якщо компілятор робить вирівнювання на межі абзацу, то структура (об’єднання) типу ArraysOfChars:
// структура, що містить 2 рядки
struct ArrayOfChars
{
    char A[10];
    char B[8];
};

може займати в пам’яті 24 байти. Тому що для масиву A виділяється 16 байт а не 10 байт. Компілятор додатково виділяє 6 байт щоб реалізувати вирівнювання на межі абзацу.

Таким чином, використання операції sizeof() для визначення типу структури чи об’єднання гарантує переносність програмного коду.


Зв’язані теми