Объединения
На структуры во многом похожи объединения. Объединения также хранят набор элементов, но в отличие от структуры все элементы объединения имеют нулевое смещение. А это значит, что разные элементы занимают в памяти один и тот же участок.
Для определения объединений применяется ключевое слово union и следующий формальный синтаксис:
1
2
3
4
union имя_объединения
{
определения_элементов
};
Фактически объединение определяется точно также, как и структура, только вместо слова struct используется ключевое слово union.
Так, создадим простейшее объединение:
1
2
3
4
5
union code
{
int digit;
char letter;
};
Объединение code хранит в одном и том же участки памяти объект int и объект char. Конкретный размер выделенной памяти будет зависеть от системы и реализации, но в общем случае это будет выглядеть примерно следующим образом:
Объединение union в языке программирования Си
В этом случае объединение сode на большинстве платформ будет занимать 4 байта. Длина элементов, как здесь, может быть разной, и в этом случае размер объединения вычисляется по наибольшему элементу.
После определения объединения мы можем создать его переменную и присвоить ей какое-либо значение:
1
union code id;
При определении переменной объединения мы ее можем сразу инициализировать, но стоит учитывать, что инициализировать мы можем только первый элемент объединения. В данном случае это элемент digit типа int, поэтому мы можем передать ему только целое число:
1
union code id = {120};
Для обращения к элементам объединения, как и в случае со структурами, можно использовать операцию "точка":
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
typedef union code
{
int digit;
char letter;
};
int main(void)
{
union code id;
id.digit = 120;
printf("%d - %c \n", id.digit, id.letter); // 120 - x
printf("%d - %d \n", id.digit, id.letter); // 120 - 120
id.letter = 87;
printf("%d - %c \n", id.digit, id.letter); // 87 - W
return 0;
}
Стоит отметить, что, так как оба элемента занимают одну и ту же память, то изменение одного из них приведет к изменению другого. Так так участок памяти один, и данные фактически одни и те же, только при обращении к id.digit данные интерпретируются как объект int, а при обращении к id.letter - как объект char.
С помощью оператора typedef можно задать псевдоним для объединения:
1
2
3
4
5
typedef union code
{
int digit;
char letter;
} secret_code;
Здесь псевдонимом является идентификатор secret_code, поэтому следующие определения переменных будут аналогичны:
1
2
union code id = {22};
secret_code id2 = {22};
Также можно определять анонимные объединения:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
union
{
int digit;
char letter;
} id1, id2; // переменные id1, id2
int main(void)
{
id1.digit = 122;
id2.digit = 84;
printf("%d - %c \n", id1.digit, id1.letter);
printf("%d - %c \n", id2.digit, id2.letter);
return 0;
}
И как и со структурами, можно определять указатели на объединения. Для обращения к элементам объединения по указателю применяется тот же синтаксис, что и в случае со структурами:
1
2
(* указатель_на_объединение).имя_элемента
указатель_на_объединение->имя_элемента
Используем указатели на объединения:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
union code
{
int digit;
char letter;
};
int main(void)
{
union code id = {45};
union code * p_id = &id;
printf("%d \n", p_id->digit); // 45
p_id->digit= 89;
printf("%d \n", id.digit); // 89
return 0;
}