Ответ
union — это составной тип данных в C++, все члены которого разделяют одну и ту же область памяти. Размер union равен размеру его наибольшего члена. В один момент времени union может содержать значение только одного из своих членов.
Основное применение: экономия памяти и низкоуровневая работа с данными (например, представление одних и тех же байтов разными типами).
#include <iostream>
union DataPacket {
int32_t asInt;
float asFloat;
uint8_t asBytes[4];
};
int main() {
DataPacket packet;
packet.asFloat = 3.14159f;
// Интерпретируем те же байты как целое число
std::cout << "Float value: " << packet.asFloat << std::endl;
std::cout << "Same bits as integer: 0x" << std::hex << packet.asInt << std::endl;
// Доступ к отдельным байтам
std::cout << "Bytes: ";
for (int i = 0; i < 4; ++i) {
std::cout << static_cast<int>(packet.asBytes[i]) << ' ';
}
std::cout << std::endl;
return 0;
}
Важные замечания:
- Активен только один член union. Чтение неактивного члена — это неопределенное поведение (UB).
- В современном C++ (C++11 и выше) рекомендуется использовать объединения с вариантом (variant unions), где можно явно отслеживать активный член, или стандартный класс
std::variant. - Часто используется в системном программировании, для работы с регистрами оборудования или разбора сетевых пакетов.
Ответ 18+ 🔞
Давай разберёмся с этим union, а то народ часто нихуя не понимает, зачем эта штука вообще нужна. Представь себе, что у тебя есть одна комната, но в неё можно поставить либо диван, либо кровать, либо шкаф. Всё сразу — никак, места хватит только на что-то одно. Вот union — это такая же комната в памяти, только для данных.
Короче, суть: это тип, где все переменные-члены делят одну и ту же память. Размер union'а равен размеру самого большого его члена. И в один момент времени там живёт значение только одного из них. Если записал в один член, а читаешь из другого — это пиздец, неопределённое поведение, ёпта. Компилятор тебя не остановит, но результат будет — хуй с горы.
Зачем это надо, спросишь? Ну, во-первых, чтобы память экономить, если тебе нужно хранить что-то одно из нескольких вариантов. Во-вторых, для всяких низкоуровневых фокусов — посмотреть на одни и те же байты под разными соусами.
#include <iostream>
union DataPacket {
int32_t asInt;
float asFloat;
uint8_t asBytes[4];
};
int main() {
DataPacket packet;
packet.asFloat = 3.14159f;
// Смотрим на те же байты, но как на целое число
std::cout << "Float value: " << packet.asFloat << std::endl;
std::cout << "Same bits as integer: 0x" << std::hex << packet.asInt << std::endl;
// Лезем прямо в отдельные байты
std::cout << "Bytes: ";
for (int i = 0; i < 4; ++i) {
std::cout << static_cast<int>(packet.asBytes[i]) << ' ';
}
std::cout << std::endl;
return 0;
}
Важные моменты, которые надо помнить, а то будет хиросима:
- Активен только один член. Записал в
asFloat— работай сasFloat. Если сразу после этого начнёшь читатьasInt— это чистой воды русская рулетка, неопределённое поведение. Может повезёт, а может и нет, ядрёна вошь. - В современном C++ (C++11 и дальше) для таких штук лучше использовать объединения с вариантом (variant unions), где можно явно указать, какой член сейчас активен, или вообще взять
std::variantиз стандартной библиотеки — он безопаснее и понятнее. - Где это реально применяется? Да в основном в системняке: разбор сетевых пакетов, работа с регистрами какого-нибудь железа, когда нужно одни и те же биты интерпретировать по-разному. В обычном прикладном коде — редкость, потому что доверия к этой конструкции ебать ноль, легко накосячить.