Как хранятся члены профсоюза? - PullRequest
14 голосов
/ 27 декабря 2010
union test
{
 int i;
 char ch;
}t;
int main()
{
 t.ch=20;
}

Предположим, sizeof(int)==2 и пусть адресам памяти, выделенным для t, являются 2000, 2001.
Тогда где хранится 20, т.е. t.ch - в 2000 или 2001 или зависит от порядкового номера машины?

Ответы [ 2 ]

20 голосов
/ 27 декабря 2010

Стандарт C99 (§6.7.2.1.14) гласит:

Размер союза достаточен, чтобы вместить самого большого из его членов. Значение в большинство из членов могут быть сохранены в объекте объединения в любое время. Указатель на Объект объединения, соответствующим образом преобразованный, указывает на каждого из его членов (или, если член является битовым поле, затем к единице, в которой он находится), и наоборот.

(выделение добавлено)

В смелом утверждении фактически говорится, что каждый член союза имеет один и тот же адрес, поэтому все они «начинаются» с одного и того же адреса. t, как t.ch, как t.i, должно быть по адресу 2000, таким образом t.ch перекрывается с первым байтом (в порядке адресов) t.i.

Что это означает с точки зрения «что я получу, если я попытаюсь прочитать t.i после установки t.c» в реальном мире, зависит от порядкового номера платформы и от фактов, пытающихся прочитать члена союза, когда вы в другом написано «Неопределенное поведение в соответствии со стандартом C» (§6.2.6.1.6 / 7, пересмотренное в §J.1.1).

<ч />

Что помогает понять псевдоним машины (по крайней мере, я думаю, что это более просто понять), так это иметь такой союз:

union
{
    int i;
    unsigned char ch[sizeof(i)];
} t;

делает

t.i=20;

и затем посмотрим, что внутри двух символов в t.ch. Если вы находитесь на машине с прямым порядком байтов, вы получите t.ch[0]==20 и t.ch[1]==0, и наоборот, если вы находитесь на машине с прямым порядком байтов (если sizeof(int)==2). Обратите внимание, что, как уже было сказано, это конкретная реализация, в стандарте даже не упоминается порядковый номер.

Чтобы сделать его еще более понятным: если у вас есть 2-байтовый int var, установленный в 20, на машине с прямым порядком байтов, дамп памяти, связанный с ним в порядке адресов, вы получите (в шестнадцатеричном представлении , байты разделены пробелом):

14 00

на машине с прямым порядком байтов вы получите

00 14

Представление с прямым порядком байтов выглядит "более правильным" с нашей точки зрения, потому что в представлении с прямым порядком байтов байты, составляющие int, хранятся в обратном порядке.

<ч />

Более того, я говорю, что если я сделаю это:

int a=20;
printf("%d",* (char*)&a);

Тогда результат не зависит от порядка байтов, т. Е. Хранится ли 20 в 2000 или 2001?

Да, вот так, но в своем вопросе вы спрашиваете другое; это выглядит более мой пример.

1 голос
/ 27 декабря 2010

test будет занимать два байта и будет выделен по адресу 2000, 2002 и т. Д. И любое значение для каждого экземпляра объединения будет храниться, начиная с этого базового адреса.

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

...