2010-12-27 2 views
12
union test 
{ 
int i; 
char ch; 
}t; 
int main() 
{ 
t.ch=20; 
} 

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

+0

Я не уверен, что endian-ness имеет какое-либо отношение к тому, где хранится объединение ... не все ли типы объединения хранятся в одном и том же месте (т. Е. При смещении нуля)? (Хороший вопрос, хотя!) –

+3

2001 маловероятно, так как неравномерный доступ к памяти либо медленный, либо запрещенный в зависимости от архитектуры. –

+0

@Platinum Azure: если мы просто определим int a = 20; то разве это не зависит от того, где 20 хранится? –

ответ

18

Стандарт 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 

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

00 14 

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


Кроме того, я хочу сказать, что если я делаю это:

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

Тогда не выход зависит от порядок байтов т.е. ли 20 хранится в 2000 или 2001 ?

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

+0

Спасибо Matteo. На самом деле вы и Platinum Azure высказываете противоположные вещи, поэтому я был в замешательстве. –

+1

@Happy Mittal: Как я объяснил в своем последнем комментарии, но это, я использовал старый комментарий, который имел преобразование int-to-char. Факт остается фактом: шестнадцатибитное число, представленное буквальным '20', по-прежнему сохраняется в байтах BOTH, независимо от того, какая консистенция использует ваша архитектура. Просто один байт или другой будет равен нулю. Если вы должны были сохранить число, подобное '257', оба байта будут отличными от нуля. –

1

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

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