У меня есть следующее определение типа:
typedef union{
unsigned int Entry;
struct {
unsigned char EntryType;
unsigned char EntryOffset[3];
};
} TLineDescriptor;
У меня также есть следующее использование типа:
TLineDescriptor LineDescriptor;
LineDescriptor.Entry = 40;
LineDescriptor.EntryType = 0x81;
sizeof(LineDescriptor)
показывает, что эта переменная занимает 4 байта памяти, что вначале я предполагал, что она содержит либо int, либо struct.
cout << LineDescriptor.Entry << " " << LineDescriptor.EntryType << endl;
Тем не менее, строка выше печатает два разных значения, а именно 129 ü
, LineDescriptor.Entry
по-видимому, относится к области памяти, где было сохранено значение 0x81. Я не уверен, что случилось с 40.
Но ясно, что мое предположение было неверным. Может ли кто-то правильно интерпретировать и объяснить определение типа? Понимание этого крайне важно для меня, чтобы работать с кодом, который я нашел.
Заранее спасибо.
Это не разные значения, на самом деле. 129
код символа для символа ü
, operator <<
из ostream
лечит int
а также char
типы данных по-разному, печатая числовое значение для первого и символьное значение для последнего.
Итак, ваше понимание типов объединений верно. Тем не менее, обратите внимание, что при работе с типами union может возникнуть проблема с порядком байтов. Например, на машинах с прямым порядком байтов EntryType
будет содержать наименее значимый байт Entry
и EntryOffset
массив других. Но на машинах с прямым порядком байтов, EntryType
будет содержать самый значимый байт.
Ваше предположение не так, профсоюз проведет или Int или структура. Когда вы назначаете значение 0x81
в поле EntryType — целое число, которое вы ранее присвоили Entry
будет перезаписано, поэтому, когда вы cout
В обоих полях вы получите одинаковое количество, отображаемое для обоих: одно как int (129), а другое как char (ü). Оба имеют шестнадцатеричное значение 0x81
,
Это держит int
и struct
на так же время, и оба занимают одно и то же пространство памяти. Получив доступ TLineDescriptor::Entry
Вы интерпретируете эти 4 байта как int
, Если вы получаете доступ к нему через struct
Вы интерпретируете это как 4 unsigned char
s.
LineDescriptor.Entry = 40;
Это устанавливает 4 байта в int
значение 40. В системе с прямым порядком байтов это означает, что первый байт равен 40, остальные 3 байта равны 0.
LineDescriptor.EntryType = 0x81;
Это устанавливает первый байт в значение 129 (0x81). (В системе с прямым порядком байтов это означает, что значение Entry
теперь также 129, при условии, что для остальных установлено значение 0).
Что касается другого вывода: когда вы выводите EntryType, он отображается в виде символа, а не числа. Пытаться:
cout << LineDescriptor.Entry << " " << static_cast<int>(LineDescriptor.EntryType) << endl;
Напечатайте EntryType следующим образом:
cout << "0x" << hex << (unsigned)LineDescriptor.EntryType << endl;
и вы увидите, что ü равно 0x81.
Печать этого:
cout << LineDescriptor.Entry
является неопределенным поведением — потому что только один элемент в объединении может быть «активным» в данный момент — и ваше последнее назначение было EntryType.
Однако если предположить, что мы можем предположить, что это на самом деле не так неопределенно, как хотелось бы C ++, тогда 129 получен из:
Entry=40
— который в двоичном формате в вашей системе 28 00 00 00
(младший байт первый).
С LineDescriptor.EntryType = 0x81;
Вы изменили первый байт: 81 00 00 00
— так что ваша распечатка для Entry теперь 129.
Проведите этот эксперимент, и вы получите другой результат:
TLineDescriptor LineDescriptor;
LineDescriptor.Entry = 256;
LineDescriptor.EntryType = 0x81;
cout << LineDescriptor.Entry << " " << unsigned(LineDescriptor.EntryType)
<< endl;
>> 385 129