Язык программирования C++ для профессионалов


Объединения


Рассмотрим таблицу имен, в которой каждый элемент содержит имя и его значение. Значение может задаваться либо строкой, либо целым числом:

struct entry { char* name; char type; char* string_value; // используется если type == 's' int int_value; // используется если type == 'i' }; void print_entry(entry* p) { switch(p->type) { case 's': cout << p->string_value; break; case 'i': cout << p->int_value; break; default: cerr << "type corrupted\n"; break; } }

Поскольку переменные string_value и int_value никогда не могут использоваться одновременно, очевидно, что часть памяти пропадает впустую. Это можно легко исправить, описав обе переменные как члены объединения, например, так:

struct entry { char* name; char type; union { char* string_value; // используется если type == 's' int int_value; // используется если type == 'i' }; };

Теперь гарантируется, что при выделении памяти для entry члены string_value и int_value будут размещаться с одного адреса, и при этом не нужно менять все части программы, работающие с entry. Из этого следует, что все члены объединения вместе занимают такой же объем памяти, какой занимает наибольший член объединения.

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

Иногда объединения используют для "псевдопреобразований" типа (в основном на это идут программисты, привыкшие к языкам, в которых нет средств преобразования типов, и в результате приходится обманывать транслятор). Приведем пример такого "преобразования" int в int* на машине VAX, которое достигается простым совпадением разрядов:




Начало  Назад  Вперед