union test
{
int i;
char ch;
}t;
int main()
{
t.ch=20;
}
Предположим sizeof(int)==2
, и адреса памяти, выделенные для t, - 2000, 2001.
Тогда где 20 i.e. t.ch
хранится - в 2000 или 2001 году или зависит от конечности машины?
union test
{
int i;
char ch;
}t;
int main()
{
t.ch=20;
}
Предположим sizeof(int)==2
, и адреса памяти, выделенные для t, - 2000, 2001.
Тогда где 20 i.e. t.ch
хранится - в 2000 или 2001 году или зависит от конечности машины?
В стандарте C99 (§6.7.2.1.14) говорится:
Размер объединения достаточен, чтобы содержать самый большой из его членов. Значение at большинство из них могут быть сохранены в объединенном объекте в любое время. Указатель на объединенный объект, соответствующим образом преобразованный, указывает на каждый из его членов (или если член является бит- поле, затем в блок, в котором он находится) и наоборот.
(выделено курсивом)
Смелое утверждение на самом деле говорит о том, что каждый член союза имеет один и тот же адрес, поэтому все они "начинаются" по одному и тому же адресу. t
, как t.ch
как t.i
, должен находиться в адресе 2000, поэтому t.ch
перекрывается с первым байтом (в адресном порядке) t.i
.
Что это означает в терминах "что я получу, если попытаюсь прочитать t.i
после установки t.c
" в реальном мире, зависит от конечности платформы и в фактах, пытающихся прочитать член союза, когда вы в другом - это неспецифицированное поведение в соответствии со стандартом C (§6.2.6.1.6/7, переформулированное в § 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, на машине little-endian, сбросив связанную с ним память в адресном порядке, вы получите (в шестнадцатеричном представлении, байты, разделенные пробелом):
14 00
пока на большой машине вы получите
00 14
Представление с большой буквы выглядит "более правильным" с нашей точки зрения, потому что в маленьком концевом представлении байты, которые составляют все int
, хранятся в обратном порядке.
Кроме того, я говорю, что если я это сделаю:
int a=20;
printf("%d",* (char*)&a);
Тогда не зависит результат от конечности, то есть, 20 хранится ли в 2000 или 2001 году?
Да, вот оно, но в вашем вопросе вы спрашиваете другую вещь; это больше похоже на мой пример.
test будет принимать два байта и поэтому будет выделен по адресу 2000, 2002 и т.д. И любое значение для каждого экземпляра объединения будет сохранено, начиная с этого базового адреса.
Каждый член союза будет храниться по тому же адресу для этого экземпляра объединения. Поэтому вы можете хранить только один тип значения в объединении одновременно. Следовательно, объединения занимают количество байтов, необходимых для самого большого члена.