Бьерн Страуструп. Язык программирования С++ Второе дополненное издание



Pdf көрінісі
бет64/256
Дата11.07.2022
өлшемі2,87 Mb.
#37591
1   ...   60   61   62   63   64   65   66   67   ...   256
2.6.2. Объединения 
Рассмотрим таблицу имен, в которой каждый элемент содержит имя и его значение. Значение может 
задаваться либо строкой, либо целым числом: 
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. 
Из этого следует, что все члены объединения вместе занимают такой же объем памяти, какой занимает 
наибольший член объединения. 
Надежный способ работы с объединением заключается в том, чтобы выбирать значение с помощью 
того же самого члена, который его записывал. Однако, в больших программах трудно гарантировать, 
что объединение используется только таким способом, а в результате использования не того члена 
обЪединения могут возникать трудно обнаруживаемые ошибки. Но можно встроить объединение в 
такую структуру, которая обеспечит правильную связь между значением поля типа и текущим типом 
члена объединения ($$5.4.6). 
Иногда объединения используют для "псевдо-преобразований" типа (в основном на это идут 
программисты, привыкшие к языкам, в которых нет средств преобразования типов, и в результате 
приходится обманывать транслятор). Приведем пример такого "преобразования" int в int* на машине 
VAX, которое достигается простым совпадением разрядов: 
struct fudge { 
union 



Бьерн Страуструп.
Язык программирования С++ 
 
68 
int 
i; 
int* 
p; 
}; 
}; 
fudge a; 
a.i = 4095; 
int* p = a.p; 
// некорректное использование 
В действительности это вовсе не преобразование типа, т.к. на одних машинах int и int* занимают 
разный объем памяти, а на других целое не может размещаться по адресу, задаваемому нечетным 
числом. Такое использование объединений не является переносимым, тогда как существует 
переносимый способ задания явного преобразования типа ($$3.2.5). 
Иногда объединения используют специально, чтобы избежать преобразования типов. Например, можно 
использовать fudge, чтобы узнать, как представляется указатель 0: 
fudge.p = 0; 
int i = fudge.i; 
// i необязательно должно быть 0 
Объединению можно дать имя, то есть можно сделать его полноправным типом. Например, fudge 
можно описать так: 
union fudge { 
int i; 
int* 
p; 
}; 
и использовать (некорректно) точно так же, как и раньше. Вместе с тем, поименованные объединения 
можно использовать и вполне корректным и оправданным способом (см. $$5.4.6). 


Достарыңызбен бөлісу:
1   ...   60   61   62   63   64   65   66   67   ...   256




©emirsaba.org 2024
әкімшілігінің қараңыз

    Басты бет