Объединения. Ключевое слово 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 *p; // неуправляемый указатель

// выделить память для объединения
p = 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() для определения типа структуры или объединения гарантирует переносность программного кода.


Связанные темы