Определение объединения и переменной объединяющего типа

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

Определим переменную UNI объединяющего типа с помощью анонимного шаблона:

union {

long L;

unsigned i1;

int i2;

char c[4];

}UNI;

 

Схема размещения переменной UNI в памяти:

long L

                             

unsigned i1

int i2

char c[4]

 

т.е. элементы располагаются с одного адреса. Это подтвердит и выполнение следующих операторов:

cout << &UNI.L; //все переменные имеют один и тот же адрес

cout << &UNI.i1;

cout << &UNI.i2;

cout << &UNI.c;

 

Размер памяти, выделяемый объединению, равен максимальному из размеров памяти, выделяемых для отдельных полей шаблона. Тип поля может быть любым, в том числе и структурой. Структуры могут быть членами объединения, и объединение может быть членом структуры. Разрешается создание и массива объединений.

Переменные типа объединение могут быть формальными параметрами и аргументами вызова функций. Чтобы функция не изменила аргумент-объединение при передаче по указателю или ссылке, соответствующий параметр объявляется со спецификатором const. Функция может возвращать переменную-указатель или ссылку типа объединение.

Доступ к полям объединения выполняется, аналогично структурам, через уточненное имя:

имя_объединения.имя_поля

(*указатель_на_объединение).имя_поля

указатель_на_объединение->имя_поля

ссылка_на_объединение.имя_поля

 

Внимание!!! Члены-данные анонимного объединения можно использовать как переменные(если их имена уникальны в контексте объявления). Например:

enum week {sun, mon, tues, weds, thurs, fri, sat};

union {// анонимное объединение

int i;

week w;

};

i = 6; if ((w == sun) || (w == sat)) cout << “Это выходные дни!”;

 

Объединения могут быть опасны, так как их реализация часто зависит от системы.

 

Если бы элементы объединения имели одинаковую длину и одинаковый тип, а отличались только именами, то использование объединения было бы подобно применению ссылок: один участок памяти имел бы несколько различных имен.

 

Заносить значения в участок памяти, выделенный для объединения, можно с помощью любого из элементов:

union {

int ival;

float fval;

char cval[4];

} uval;

Переменной uval можно присваивать любой из трех типов; какой тип в данный момент находится в переменной – должен помнить программист.

Но:

инициализироваться объединение может только первым описанным полем.

Инициализатор объединения – значение для его первого члена, заключенное в фигурные скобки. Например:

union int_flt {

int i;

float x;

} n = {0}; // член (поле) i инициализируется нулем.

 

n.i = 7; //в объединение записано целое значение

cout << n.i << endl; // объединение интерпретируется как имеющее целый тип

n.x = 7.0; // в объединение записано вещественное значение

cout << n.x << endl; //объединение интерпретируется как имеющее вещественный тип

 

Основное достоинство объединений – возможность разных трактовок одного и того же содержимого памяти.

Пусть имеем объединение:

union

{float f;

unsigned long k;

} FK;

 

Можно присвоить объединению вещественное значение FK.f = -256.5, а рассматривать его затем как беззнаковое целое:

cout << hex << FK.k; //получим с380400016.

 

Если же включить в шаблон объединения массив:

union

{double f;

char h[8];

} FLH;

 

и выполнить присваивание вещественного значения переменной FLH присваиванием этого значения полю FLH.f, то имеем возможность доступа к отдельным байтам внутреннего представления этого значения с помощью имен FLH.h[0], FLH.h[1], и т.д.