Инициализация соединения и структуры
Я наткнулся на код, основанный на объединениях в C. Вот код:
union {
struct {
char ax[2];
char ab[2];
} s;
struct {
int a;
int b;
} st;
} u ={12, 1};
printf("%d %d", u.st.a, u.st.b);
Я просто не мог понять, как получилось 268 0
. Как инициализировались значения?
Как здесь функционирует профсоюз? Не должно быть выхода 12 1
. Было бы здорово, если бы кто-нибудь мог объяснить, что именно здесь происходит подробно.
Я использую 32-битный процессор и Windows 7.
Ответы
Ответ 1
Код не делает то, что вы думаете. Логически инициализируется инициализация первого члена объединения, т.е. u.s
. Однако теперь инициализатор является неполным и отсутствует фигурные скобки, так как u.s
содержит два массива. Это должно быть что-то вроде: u = { { {'a', 'b'}, { 'c', 'd' } } };
Вы всегда должны компилироваться со всеми предупреждениями, достойный компилятор должен был сказать вам, что что-то не так. Например, GCC говорит, missing braces around initialiser (near initialisation for ‘u.s’)
и missing initialiser (near initialisation for ‘u.s.ab’)
. Очень полезно.
В C99 вы можете использовать инициализацию именованного члена для инициализации второго члена объединения: u = { .st = {12, 1} };
(Кстати, это невозможно в С++). Соответствующий синтаксис для первого случая - `u = { .s = { {'a', 'b'}, { 'c', 'd' } } };
, который возможно более ясный и читаемый!
Ответ 2
В вашем коде используется инициализатор по умолчанию для объединения, который является его первым членом. Оба 12 и 1 входят в символы топора, следовательно, результат, который вы видите (что очень зависит от компилятора).
Если вы хотите инициализировать второй memmber (st
), вы должны использовать назначенный инициализатор:
union {
struct {
char ax[2];
char ab[2];
} s;
struct {
int a;
int b;
} st;
} u ={ .st = {12, 1}};
Ответ 3
Коды устанавливают u.s.ax[0]
в 12 и u.s.ax[1]
в 1. u.s.ax
накладывается на u.st.a
, поэтому младший старший байт u.st.a
устанавливается равным 12, а самый старший байт - 1 ( поэтому вы должны работать на архитектуре little-endian), давая значение 0x010C или 268.
Ответ 4
Вероятно, он назначил {12, 1} первым 2 char в s.ax.
Итак, в 32-битном int это 1 * 256 + 12 = 268
Ответ 5
Размер объединения - это максимальный размер самого большого элемента, который объединяет объединение. Таким образом, в этом случае ваш тип объединения имеет размер 8 байтов на 32-битной платформе, где типы int
- по 4 байта. Первый член объединения s
, однако, занимает всего 2 байта и, следовательно, перекрывается с первым 2-байтом члена st.a
. Поскольку вы находитесь в системе little-endian, это означает, что мы перекрываем два младших байта st.a
. Таким образом, когда вы инициализируете объединение, как это делается со значениями {12, 1}
, вы только инициализировали значения в двух младших байтах st.a
... это оставляет значение st.b
, инициализированное значением 0
. Таким образом, при попытке распечатать структуру, содержащую двух членов int
, а не char
объединения, вы получите результаты 128
и 0
.