Union c что это
На структуры во многом похожи объединения. Объединения (union) также позволяют определить свой тип данных и также хранят набор элементов, но в отличие от структуры все элементы объединения имеют нулевое смещение. А это значит, что разные элементы занимают в памяти один и тот же участок, то есть в памяти они накладываются друг на друга.
Для определения объединений применяется ключевое слово union и следующий формальный синтаксис:
Фактически объединение определяется точно также, как и структура, только вместо слова struct используется ключевое слово union .
Так, создадим простейшее объединение, которое хранит символ и его числовой код из таблицы ASCII:
Объединение ascii хранит в одном и том же участки памяти объект int (числовой код символа) и объект char (сам символ). Конкретный размер выделенной памяти будет зависеть от системы и реализации, но в общем случае это будет выглядеть примерно следующим образом:
В этом случае объединение сode на большинстве платформ будет занимать 4 байта. Длина элементов, как здесь, может быть разной, и в этом случае размер объединения вычисляется по наибольшему элементу.
После определения объединения мы можем создать его переменную и присвоить ей какое-либо значение:
При определении переменной объединения мы ее можем сразу инициализировать, но стоит учитывать, что инициализировать мы можем только первый элемент объединения. В данном случае это элемент digit типа int, поэтому мы можем передать ему только целое число:
Для обращения к элементам объединения, как и в случае со структурами, можно использовать операцию «точка»:
Здесь создается переменная code, которая представляет объединение ascii. Далее его элементу digit (числовой код символа) присваивается число 120:
Стоит отметить, что, так как оба элемента — letter и digit занимают одну и ту же память, то данные фактически одни и те же, только при обращении к code.digit данные интерпретируются как объект int, а при обращении к code.letter — как объект char.
И изменение одного из них приведет к изменению другого.
С помощью оператора typedef можно задать псевдоним для объединения:
Здесь псевдонимом является идентификатор ascii_code , поэтому следующие определения переменных будут аналогичны:
Также можно определять анонимные объединения:
И как и со структурами, можно определять указатели на объединения. Для обращения к элементам объединения по указателю применяется тот же синтаксис, что и в случае со структурами:
C++. Объединения. Ключевое слово union. Примеры объявления и использования объединений
Объединения. Ключевое слово union . Примеры объявления и использования объединений
Содержание
- 1. Что такое объединение в языке C++? Для чего используются объединения?
- 2. Как выглядит общая форма объявления типа (шаблона) объединения? Ключевое слово union
- 3. Что такое длина объединения? Как вычисляется длина объединения?
- 4. Как объявить тип (шаблон) объединения и переменную этого типа? Пример
- 5. Как осуществляется доступ к полям объединения?
- 6. Пример объявления и использования указателя (*) на объединение
- 7. Как объявить вложенные объединения (структуры, классы) в шаблоне объединения? Пример
- 8. Как описать массив объединений? Пример
- 9. Какие особенности применения операции sizeof() для объединений и структур?
- имя_типа_объединения – непосредственно имя новосозданного типа;
- переменная1 , переменная2 , переменнаяN – переменные, которые есть полями объединения. Эти переменные могут быть разных типов;
- тип – тип переменной, который есть полем объединения.
- тип структура ;
- тип объединения;
- тип класс.
- с помощью символа ‘ . ‘ ;
- с помощью последовательности символов ‘->’ в случае, когда объявлена переменная-указатель на объединение.
- размеры некоторых встроенных типов (например тип int ) могут быть разными для разных компьютеров. Например, на одних платформах для типа int будет выделено 2 байта, на других 4 байта;
- компилятор делает так называемое «выравнивание памяти» на границе слова (2 байта) или абзаца (16 байт). Например, если компилятор делает выравнивание на границе абзаца, то структура (объединение) типа ArraysOfChars :
Поиск на других ресурсах:
1. Что такое объединение в языке C++? Для чего используются объединения?
Объединение – это группирование переменных, которые разделяют одну и ту же область памяти. В зависимости от интерпретации осуществляется обращение к той или другой переменной объединения. Все переменные, что включены в объединение начинаются с одной границы.
Объединение позволяет представить в компактном виде данные, которые могут изменяться. Одни и те же данные могут быть представлены разными способами с помощью объединений.
Точно также как и структуры , объединения требуют объявления типа (шаблона) и объявления переменной этого типа.
2. Как выглядит общая форма объявления типа (шаблона) объединения? Ключевое слово union
Объявление объединения (типа объединения или шаблона объединения) начинается с ключевого слова union .
Тип переменной может быть:
-
, принятым в языке C++/CLI;
3. Что такое длина объединения? Как вычисляется длина объединения?
Длина объединения – это размер памяти в байтах, которая выделяется для одной переменной этого типа объединения.
Длина объединения вычисляется как максимум из всех длин (размеров в байтах) отдельных полей шаблона. Следует напомнить, что одно поле – это объявление одной переменной в объединении (см. п. 2).
4. Как объявить тип (шаблон) объединения и переменную этого типа? Пример
Пусть задан тип объединения, которое содержит переменные типов с плавающей точкой
Тип объединения Floats содержит 2 переменные с именами f и d . Переменная f есть типа float, переменная d есть типа double . Для переменной f типа float рассматривается (принимается во внимание) 4 байта. Для переменной d типа double принимается во внимание 8 байт, так как компилятор выделяет для этого типа именно 8 байт.
Чтобы использовать объединение Floats в другом программном коде (методе, обработчике события и т.п.) нужно объявить переменную типа Floats как показано ниже
Поскольку размещение переменных в памяти условно начинается с одного адреса, то для переменной Fl типа Floats выделяется 8 байт памяти. Это связано с тем, что переменная типа double требует больше памяти для своего представления чем переменная типа float .
На рисунке 1 отображено размещение (интерпретация) переменных f , d из объединения Floats .

Рис. 1. Представление переменных f , d в объединении Floats
5. Как осуществляется доступ к полям объединения?
Доступ к полям объединения осуществляется так же, как и для структуры:
6. Пример объявления и использования указателя ( * ) на объединение
Работа объединений с неуправляемыми ( * ) указателями точно такая же, как и работа структур с неуправляемыми указателями .
В нижеследующем примере объявляется неуправляемый указатель на объединение типа Ints
7. Как объявить вложенные объединения (структуры, классы) в шаблоне объединения? Пример
Шаблон объединения может включать поля, что есть структурами, объединениями и классами.
В примере ниже объявляется шаблон объединения с именем Types , содержащий два вложенных объединения Floats и Ints , структуру ArrayOfChars и класс MyPoint .
Объявление структур и объединений имеет следующий вид
Объявление шаблона класса имеет следующий вид:
Объявление типа объединение Types с вложенными сложными типами Ints , Floats , ArrayOfChars , MyPoint .
Использование объединения Types в некотором программном коде:
8. Как описать массив объединений? Пример
9. Какие особенности применения операции sizeof () для объединений и структур?
В программах на C++ для определения размера переменной типа «структура» или «объединение» обязательно нужно использовать операцию sizeof . Определение размера «вручную» есть ошибочным поскольку:
может занимать в памяти 24 байта. Так как для массива A выделяется 16 байт а не 10 байт. Компилятор дополнительно выделяет 6 байт чтобы реализовать выравнивание на границе абзаца.
Таким образом, использование операции sizeof() для определения типа структуры или объединения гарантирует переносность программного кода.
Union c что это
Like Structures, union is a user defined data type. In union, all members share the same memory location.

For example in the following C program, both x and y share the same location. If we change x, we can see the changes being reflected in y.
How is the size of union decided by compiler?
Size of a union is taken according the size of largest member in union.
Pointers to unions?
Like structures, we can have pointers to unions and can access members using the arrow operator (->). The following example demonstrates the same.
What are applications of union?
Unions can be useful in many situations where we want to use the same memory for two or more members. For example, suppose we want to implement a binary tree data structure where each leaf node has a double data value, while each internal node has pointers to two children, but no data. If we declare this as:
then every node requires 16 bytes, with half the bytes wasted for each type of node. On the other hand, if we declare a node as following, then we can save space.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Объединение (union) в языке C для упаковки и распаковки данных
В предыдущей статье мы обсуждали, что первоначальное применение объединений создавало общую область памяти для взаимоисключающих переменных. Однако со временем программисты широко использовали объединения для совершенно другого применения: извлечения небольших частей данных из более крупного объекта данных. В данной статье мы рассмотрим это конкретное применение объединений более подробно.
Использование объединений для упаковки/распаковки данных
Члены объединения хранятся в общей области памяти. Это ключевая особенность, которая позволяет нам находить интересные применения для объединений.
Рассмотрим объединение, приведенное ниже:
Внутри этого объединения содержится два члена. Первый член, “ word ”, является двухбайтовой переменной. Второй член – это структура из двух однобайтовых переменных. Два байта, выделенные для объединения распределяются между двумя его членами.
Выделенное пространство памяти может быть таким, как показано ниже на рисунке 1.
Рисунок 1 – Выделенное пространство памяти для объединения, приведенного в коде выше
В то время как переменная “ word ” относится ко всему выделенному пространству памяти, переменные “ byte1 ” и “ byte2 ” относятся к однобайтовым областям, которые составляют переменную “ word ”. Как мы можем использовать эту особенность? Предположим, что у вас есть две однобайтовые переменные, “ x ” и “ y ”, которые должны быть объединены для получения одной двухбайтовой переменной.
В этом случае вы можете использовать приведенное выше объединение и присвоить значения “ x ” и “ y ” членам структуры следующим образом:
Теперь мы можем прочитать у объединения член “ word ”, чтобы получить двухбайтовую переменную, состоящую из переменных “ x ” и “ y ” (рисунок 2).
Рисунок 2 – Упаковка двух однобайтовых переменных с помощью объединения
В приведенном выше примере показано использование объединений для упаковки двух однобайтовых переменных в одну двухбайтовую переменную. Мы также можем сделать и обратное: записать двухбайтовое значение в “ word ” и распаковать его в две однобайтовые переменные, прочитав переменные “ x ” и “ y ”. Запись значения в один член объединения и чтение другого члена иногда называется «каламбуром данных» («data punning»)
Порядок байтов процессора
При использовании объединений для упаковки/распаковки данных мы должны быть осторожны с порядком байтов (endianness) процессора. Как обсуждалось в статье о порядке байтов, этот термин определяет порядок, в котором байты объекта хранятся в памяти. Процессор может быть с обратным порядком (от младшего к старшему, little endian) или с прямым порядком (от старшего к младшему, big endian). В системах с прямым порядком байтов (big endian) данные хранятся таким образом, что байт, содержащий старший значащий байт, имеет самый младший адрес памяти. В системах с обратным порядком байтов (little endian) байт, содержащий младший значащий байт, сохраняется первым.
Пример, изображенный на рисунке 3, иллюстрирует хранение последовательности 0x01020304 при обратном и при прямом порядках байтов.
Рисунок 3 – Хранение последовательности 0x01020304 при обратном и при прямом порядках байтов
Давайте поэкспериментируем с объединением из предыдущего раздела.
Запустив данный код, я получаю следующий вывод
Он показывает, что первый байт общего пространства памяти (“ u1.byte1 ”) используется для хранения наименьшего значащего байта ( 0x21 ) переменной “ word ”. Другими словами, процессор, который я использую для выполнения кода, использует обратный порядок байтов (little endian).
Как видите, это конкретное применение объединений может демонстрировать поведение, зависящее от реализации. Тем не менее, это не должно быть серьезной проблемой, потому что при таком низкоуровневом кодировании мы обычно знаем порядок байтов процессора. В случае если мы не знаем подробностей, мы можем использовать приведенный выше код, чтобы узнать, как данные организованы в памяти.
Альтернативное решение
Вместо использования объединений для выполнения упаковки или распаковки данных мы также можем использовать побитовые операторы. Например, мы можем использовать следующий код для совмещения двух однобайтовых переменных, “ byte3 ” и “ byte4 ”, и создания одной двухбайтовой переменной (“ word2 ”):
Давайте сравним вывод этих двух решений в случаях с прямым и обратным порядками байтов. Рассмотрим код, приведенный ниже:
Если мы скомпилируем этот код для процессора с прямым порядком байтов (big endian), такого как TMS470MF03107, результат будет следующим:
Однако если мы скомпилируем этот код для процессора с обратным порядком байтов (little endian), такого как STM32F407IE, результат будет следующим:
В то время как основанный на объединении код демонстрирует аппаратно-зависимое поведение, способ, основанный на операции сдвига, приводит к одному и тому же результату независимо от порядка байтов процессора. Это связано с тем, что при последнем подходе мы присваиваем значение переменной по имени (“ word2 ”), и компилятор заботится об организации памяти, используемой устройством. А с помощью метода на основе объединения мы меняем значение байтов, которые составляют переменную “ word1 ”.
Хотя основанный на объединении метод демонстрирует аппаратно-зависимое поведение, его преимущество заключается в том, что он более читабелен и удобен в поддержке. Вот почему многие программисты предпочитают использовать объединения в таком применении.
Практический пример «каламбура данных»
Выполнить упаковку или распаковку данных нам может потребоваться при работе с обычными последовательными протоколами связи. Рассмотрим протокол последовательной связи, который отправляет/принимает один байт данных во время каждого сеанса связи. Пока мы работаем с однобайтовыми переменными, данные передавать легко, но что если у нас есть структура произвольного размера, которая должна проходить через канал связи? В этом случае мы должны каким-то образом представить наш объект данных в виде массива переменных размером по одному байту. Затем на стороне получателя мы можем соответствующим образом их упаковать и восстановить исходную структуру.
Например, предположим, что нам нужно отправить канал связи UART переменную типа float , “ f1 ”. Переменная типа float обычно занимает четыре байта. Следовательно, мы можем использовать следующее объединение в качестве буфера для извлечения четырех байтов “ f1 ”.
Передатчик записывает переменную “ f1 ” в член объединения с типом float . Затем он считывает массив “ byte ” и отправляет эти байты по каналу связи. Получатель делает обратное: он записывает полученные данные в массив “ byte ” своего собственного объединения и считывает переменную объединения с типом float как полученное значение. Мы могли бы использовать этот метод для передачи объекта данных произвольного размера. Следующий код может использоваться в качестве простого теста для проверки этого метода.
Рисунок 4, приведенный ниже, визуализирует обсуждаемый метод. Обратите внимание, что байты передаются последовательно.
Рисунок 4 – Упаковка и распаковка данных при передаче и приеме через последовательный интерфейс
Заключение
В то время как изначальное применение объединений создавало общую область памяти для взаимоисключающих переменных, с течением времени программисты широко использовали объединения для совершенно другого применения: для упаковки/распаковки данных. Это конкретное применение объединений включает в себя запись значения в один член объединения и чтение другого его члена.
«Каламбур данных» («data punning») или использование объединений для упаковки/распаковки данных может привести к аппаратно-зависимому поведению. Однако его преимущество заключается в том, что оно более читабельно и удобно в поддержке. Вот почему многие программисты предпочитают использовать в этом случае объединения. «Каламбур данных» может быть особенно полезен, когда у нас есть объект данных произвольного размера, который должен передаваться через канал последовательной связи.