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

Инициализация объединения в C

Я столкнулся с этим объективным вопросом на языке программирования C. Вывод для следующего кода должен быть 0 2, но я не понимаю, почему.

Пожалуйста, объясните процесс инициализации. Здесь код:

#include <stdio.h>

int main()
{
  union a
  {
    int x;
    char y[2];
  };
  union a z = {512};
  printf("\n%d %d", z.y[0], z.y[1]);
  return 0;
}
4b9b3361

Ответ 1

Я предполагаю, что вы используете небольшую систему endian, где sizeof int is 4 bytes (32 bits), а sizeof a char - это 1 byte (8 bits), а единица, в которой целые числа представлены в двух дополнительных формах. A union имеет размер только самого большого члена, и все члены указывают на эту точную память.

Теперь вы пишете в эту память целочисленное значение 512.

512 в двоичном формате 1000000000.

или в 32-битной форме двух дополнений:

00000000 00000000 00000010 00000000.

Теперь преобразуем это в его маленькое представление конца, и вы получите:

00000000 00000010 00000000 00000000
|______| |______|
   |         |
  y[0]      y[1]

Теперь см. выше, что происходит, когда вы обращаетесь к нему с помощью индексов массива char.

Таким образом, y[0] есть 00000000, который равен 0,

и y[1] есть 00000010, который равен 2.

Ответ 2

Память, выделенная для объединения, представляет собой размер самого большого типа в объединении, который в этом случае равен int. Скажем, размер int в вашей системе равен 2 байтам, тогда

512 будет 0x200.

Репрезентация выглядит следующим образом:

0000 0010 0000 0000
|        |         |
------------------- 
Byte 1     Byte 0

Итак, первый байт 0, а второй - 2. (О малогабаритных системах)

char - один байт на всех системах.

Таким образом, доступ z.y[0] и z.y[1] равен байту доступа.

z.y[0] = 0000 0000 = 0
z.y[1] = 0000 0010 = 2

Я просто даю вам, как распределяется память, и значение сохраняется. Вам нужно учитывать приведенные ниже точки, поскольку выход зависит от них.

Точки, которые следует отметить:

  • Выход полностью зависит от системы.
  • Вопросы endianess и sizeof(int), которые будут различаться в разных системах.

PS: память, занятая обоими членами, одинакова в объединении.

Ответ 3

В стандарте говорится, что

6.2.5 Типы:

Тип объединения описывает перекрывающийся непустой набор объектов-членов, каждый из которых имеет опционально заданное имя и, возможно, отдельный тип.

Компилятор выделяет достаточно места для самого большого из членов, которые накладывают друг на друга в этом пространстве. В вашем случае память выделяется для типа данных int (предполагая 4 байта). Строка

union a z = {512};

инициализирует первый член объединения z, т.е. x становится 512. В двоичном формате он представлен как 0000 0000 0000 0000 0000 0010 0000 0000 на машине 32.

Представление памяти для этого будет зависеть от архитектуры машины. На 32-битной машине это либо будет (хранить наименее значимый байт в наименьшем адресе - Маленький Endian)

Address     Value
0x1000      0000 0000
0x1001      0000 0010
0x1002      0000 0000 
0x1003      0000 0000

или как (сохраните самый старший байт в наименьшем адресе - Big Endian)

Address     Value
0x1000      0000 0000
0x1001      0000 0000
0x1002      0000 0010 
0x1003      0000 0000

z.y[0] получит доступ к содержимому с добавлением 0x1000, а z.y[1] получит доступ к контенту по адресу 0x1001, и это содержимое будет зависеть от указанного выше представления.
Кажется, что ваша машина поддерживает представление Маленького Эндиана, и поэтому z.y[0] = 0 и z.y[1] = 2 и вывод будет 0 2.

Но, вы должны заметить, что в сноске 95 раздела 6.5.2.3 указано, что

Если элемент, используемый для чтения содержимого объекта объединения, не совпадает с элементом, используемым последним для хранения значения в объекте, то соответствующая часть представления объекта значения реинтерпретируется как представление объекта в новом типе, как описано в 6.2.6 (процесс, иногда называемый "типом" ). Это может быть представление ловушки.

Ответ 4

Размер объединения определяется максимальным размером, чтобы удерживать один его элемент. Итак, вот размер int.

Предполагая, что это 4 байта /int и 1 байт / char, можно сказать: sizeof union a = 4 bytes.

Теперь посмотрим, как он фактически хранится в памяти:

Например, экземпляр объединения, a, хранится в 2000-2003:

  • 2000 → последний (четвертый/наименее значимый/правый) байт int x, y [0]

  • 2001 → 3-й байт int x, y [1]

  • 2002 → 2-й байт int x

  • 2003 → 1-й байт int x (наиболее значимый)

Теперь, когда вы скажете z = 512:

так как z = 0x00000200,

  • M [2000] = 0x00

  • M [2001] = 0x02

  • M [2002] = 0x00

  • M [2003] = 0x00

Итак, вы печатаете, y [0] и y [1], он будет печатать данные M [2000] и M [2001], которые равны 0 и 2 в десятичной форме соответственно.

Ответ 5

Для автоматических (нестатических) элементов инициализация идентична присваиванию:

union a z;
z.x = 512;