Вы сделали это:
union NumericType Values = { 10 }; // iValue = 10
printf("%d\n", Values.iValue);
Values.dValue = 3.1416;
То, как компилятор использует память для этого объединения, аналогично использованию переменной с наибольшим размером и выравниванием (любой из них, если их несколько) и переинтерпретации приведения, когда к одному из других типов в объединении записывается / осуществляется доступ, как в:
double dValue; // creates a variable with alignment & space
// as per "union Numerictype Values"
*reinterpret_cast<int*>(&dValue) = 10; // separate step equiv. to = { 10 }
printf("%d\n", *reinterpret_cast<int*>(dValue)); // print as int
dValue = 3.1416; // assign as double
printf("%d\n", *reinterpret_cast<int*>(dValue)); // now print as int
Проблема в том, что при установке dValue на 3.1416 вы полностью перезаписали биты, которые содержали число 10. Новое значение может показаться мусором, но это просто результат интерпретации первых байтов (sizeof int) двойного 3.1416, полагая, что там есть полезное значение int.
Если вы хотите, чтобы две вещи были независимыми - так что установка double не влияет на ранее сохраненное int - тогда вы должны использовать struct
/ class
.
Это может помочь вам рассмотреть эту программу:
#include <iostream>
void print_bits(std::ostream& os, const void* pv, size_t n)
{
for (int i = 0; i < n; ++i)
{
uint8_t byte = static_cast<const uint8_t*>(pv)[i];
for (int j = 0; j < 8; ++j)
os << ((byte & (128 >> j)) ? '1' : '0');
os << ' ';
}
}
union X
{
int i;
double d;
};
int main()
{
X x = { 10 };
print_bits(std::cout, &x, sizeof x);
std::cout << '\n';
x.d = 3.1416;
print_bits(std::cout, &x, sizeof x);
std::cout << '\n';
}
Который для меня произвел этот вывод:
00001010 00000000 00000000 00000000 00000000 00000000 00000000 00000000
10100111 11101000 01001000 00101110 11111111 00100001 00001001 01000000
Важно отметить, что первая половина каждой строки показывает 32 бита, которые используются для iValue: обратите внимание, что двоичный код 1010 в младшем значащем байте (слева на процессоре Intel, подобном моему) равен 10 десятичному. Запись 3.1416 заменяет все 64-битные данные на шаблон, представляющий 3.1416 (см. http://en.wikipedia.org/wiki/Double_precision_floating-point_format). Старый шаблон 1010 перезаписывается, перекрывается, электромагнитная память не более.