Union (объединение) — это специальный тип данных, хранящий разные значения в одной и той же области памяти. В union все члены располагаются в памяти по одному и тому же адресу, и объем памяти равен размеру самого большого члена.
Использование:
Пример:
union Data { int i; float f; char s[4]; }; union Data d; d.i = 0x41424344; // в памяти теперь 4 байта, которые можно читать как int, float, строку printf("%c%c%c ", d.s[0], d.s[1], d.s[2]); // вендор-специфический вывод
Подводные камни и правила использования:
Вопрос: Каков смысл использования union, когда можно просто использовать структуру из нескольких полей?
Ответ: Использование union экономит память, потому что в любой момент внутри хранится только ОДНО значение, а не все сразу. В структуре для каждого поля выделяется память, а в union — только для максимального из полей, остальные "разделяют" эту память. Также union позволяет выполнять безопасное или намеренное преобразование между разными представлениями данных на одном фрагменте памяти.
Пример:
struct S { int i; float f; } s; // sizeof = sizeof(int) + sizeof(float) union U { int i; float f; } u; // sizeof = max(sizeof(int),sizeof(float))
История
В проекте драйвера устройства связь с "железом" велась через union с битовым доступом к данным. После небольшого рефакторинга разработчик начал писать не в то поле union, что привело к чтению неактуальных данных и фатальным сбоям системы, потому что в union только одно поле "настоящее" в каждый момент.
История
При обмене сетевыми пакетами через union для управления памятью разработчик забыл учесть выравнивание структур. В результате произошло смещение на один байт, и структура парсилась с неверными смещениями, что делало протокол несовместимым с оригиналом.
История
В работе над библиотекой сериализации программист передавал union по значению в функцию, где не инициализировалось нужное поле перед чтением. Из-за этого данные сериализовались некорректно, возникал мусор в выходном потоке, и восстановить исходную информацию было невозможно.