Подтвердить что ты не робот

Инициализация соединения и структуры

Я наткнулся на код, основанный на объединениях в 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.

4b9b3361

Ответ 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.