Стандарт отвечает на все вопросы раздела 9.5 стандарта C ++ или пункта 6.5.2.3 пункта 5 стандарта C99 (или пункта 6 стандарта C11):
В объединении самое большее один из элементов данных может быть активным в любое время, то есть значение не более одного из членов данных может быть сохранено в объединении в любое время. [Примечание: одна специальная гарантия сделана для упрощения использования объединений: если POD-объединение содержит несколько POD-структур, которые имеют общую начальную последовательность (9.2), и если объект этого типа POD-объединения содержит один из POD-структурам разрешается проверять общую начальную последовательность любого из членов POD-структуры; см. 9.2. ] Размер объединения достаточен, чтобы содержать самый большой из его элементов данных. Каждый элемент данных выделяется так, как если бы он был единственным членом структуры.
Это означает, что каждый член разделяет одну и ту же область памяти. - это не более одного активного участника, но вы не можете узнать, какой именно. Вы должны будете хранить эту информацию о текущем активном члене самостоятельно в другом месте. Хранение такого флага в дополнение к объединению (например, наличие структуры с целым числом в качестве флага типа и объединением в качестве хранилища данных) даст вам так называемое «различающееся объединение»: объединение, которое знает, какой тип в в настоящее время это «активный».
Одно из распространенных применений - лексеры, где у вас могут быть разные токены, но в зависимости от токена у вас есть различная информация для хранения (помещая line
в каждую структуру, чтобы показать, какова общая начальная последовательность):
struct tokeni {
int token; /* type tag */
union {
struct { int line; } noVal;
struct { int line; int val; } intVal;
struct { int line; struct string val; } stringVal;
} data;
};
Стандарт позволяет вам получить доступ к line
каждого члена, потому что это общая начальная последовательность каждого из них.
Существуют расширения компилятора, которые позволяют получить доступ ко всем членам независимо от того, у какого из них в данный момент хранится его значение. Это позволяет эффективно реинтерпретировать хранимые биты с различными типами среди каждого из членов. Например, для разделения переменной с плавающей точкой на 2 беззнаковых шорта можно использовать следующее:
union float_cast { unsigned short s[2]; float f; };
Это может пригодиться при написании низкоуровневого кода. Если компилятор не поддерживает это расширение, но вы все равно делаете это, вы пишете код, результаты которого не определены. Поэтому убедитесь, что ваш компилятор поддерживает его, если вы используете этот трюк.