|
Структуры
6.8. Объединения
Oбъединения - это переменная, которая в различные моменты времени может содержать объекты разных типов и размеров, причем компилятор берет на себя отслеживание размера и требований выравнивания. Объединения представляют возможность работать с различными видами данных в одной области памяти, не вводя в программу никакой машинно-зависимой информации.
В качестве примера, снова из символьной таблицы компилятора, предположим, что константы могут быть типа int, float или быть указателями на символы. значение каждой конкретной константы должно храниться в переменной соответствующего типа, но все же для управления таблицей самым удобным было бы, если это значение занимало бы один и тот же объем памяти и хранилось в том же самом месте независимо от его типа. это и является назначением объединения - выделить отдельную переменную, в которой можно законно хранить любую одну из переменных нескольких типов. Как и в случае полей, синтаксис основывается на структурах.
union u_tag { int ival; float fval; char *pval; } uval;
переменная uval будет иметь достаточно большой размер, чтобы хранить наибольший из трех типов, независимо от машины, на которой осуществляется компиляция, - программа не будет зависить от характеристик аппаратных средств. Любой из этих трех типов может быть присвоен uval и затем использован в выражениях, пока такое использование совместимо: извлекаемый тип должен совпадать с последним помещенным типом. Дело программиста - следить за тем, какой тип хранится в объединении в данный момент; если что-либо хранится как один тип, а извлекается как другой, то результаты будут зависеть от используемой машины.
Синтаксически доступ к членам объединения осуществляется следующим образом:
имя объединения.член --------------------
или
указатель объединения ->член ----------------------------
то есть точно так же, как и в случае структур. если для отслеживания типа, хранимого в данный момент в uval, используется переменная utype, то можно встретить такой участок программы:
if (utype == int) printf("%d\n", uval.ival); else if (utype == float) printf("%f\n", uval.fval); else if (utype == string) printf("%s\n", uval.pval); else printf("bad type %d in utype\n", utype);
Объединения могут появляться внутри структур и массивов и наоборот. Запись для обращения к члену объединения в структуре (или наоборот) совершенно идентична той, которая используется во вложенных структурах. Например, в массиве структур, определеным следующим образом
struct { char *name; int flags; int utype; union { int ival; float fval; char *pval; } uval; } symtab[nsym];
на переменную ival можно сослаться как
symtab[i].uval.ival
а на первый символ строки pval как
*symtab[i].uval.pval
В сущности объединение является структурой, в которой все члены имеют нулевое смещение. Сама структура достаточно велика, чтобы хранить "самый широкий" член, и выравнивание пригодно для всех типов, входящих в объединение. Как и в случае структур, единственными операциями, которые в настоящее время можно проводить с объединениями, являются доступ к члену и извлечение адреса ; объединения не могут быть присвоены, переданы функциям или возвращены ими. указатели объединений можно использовать в точно такой же манере, как и указатели структур.
Программа распределения памяти, приводимая в "лекции №8" , показывает, как можно использовать объединение, чтобы сделать некоторую переменную выровненной по определенному виду границы памяти.