Unie mogą przechowywać w jednej chwili wartość w jednej składowej, czyli:
#include
#include
using namespace std;
union spacer
{
int mil;
double metrow;
};
int main(int argc, char *argv[])
{
spacer Wojtek;
Wojtek.mil=321;
cout<<"Wojtek w milach: "<
Wojtek.metrow=100;
cout<<"Wojtek w metrach: "<
cout<<"Wojtek w milach: "<
//tak wlasnie powinno reagowac
getch();
return 0;
}
Ten przykład się zgadzał, ale jeśli zamienię w unii deklaracje składowych tzn ich typ czyli int na double i double na int, czyli:
#include
#include
using namespace std;
union spacer
{
double mil;
int metrow;
};
int main(int argc, char *argv[])
{
spacer Wojtek;
Wojtek.mil=321;
cout<<"Wojtek w milach: "<
Wojtek.metrow=100;
cout<<"Wojtek w metrach: "<
cout<<"Wojtek w milach: "<
//tak nie powinno reagowac
getch();
return 0;
}
Może ktoś wytłumaczyć czemu w tym drugim przykładzie czemu “Wojtek.mil” jest wyświetlana prawidłowa liczba a nie przypadkowa. Przecież zmieniłem drugą zmienną składową więc ta inna powinna być wymazana i przypadkowa?
Moim zdaniem dużo zależy od środowiska w którym pracujesz, czy to jest Visual Studio, DevCpp czy CodeBlock. Mi osobiście zdarzały się przypadki że przykłady z Deva nie szły w VS albo przykłady działający w CB już nie ruszał w Devie - czego się tak działo mimo że na ludzki rozum wszystko było tak jak trzeba? Pytaj mnie a ja Ciebie.
Dla double na znak jest 1 bit, wykładnik zajmuje 11 bit, mantysa 52 bit( +1 bit ukryty). Dla liczb znormalizowanych mantysa jest z przedziału <0.5;1.0).
Przy kolejności bajtów typu “little endian” wartość inta nakłada się z młodszymi 32 bitami mantysy, Tak więc masz mantysę 52-bitową i niszczysz 32 młodsze bity. Różnica może być niezauważalna przy domyślnej precyzji wypisywania liczb zmiennoprzecinkowych (szczególnie, że niekoniecznie wszystkie 32 bity sie zmieniają, w tym szczególnym przypadku może być to jedynie kilka najmłodszych bitów, da się to policzyć).
Unie nie służą do przechowywania danych w jednej składowej, tylko do danych różnych typów na jednym fragmencie pamięci. Inaczej mówiąc: unia to obszar pamięci, na którym siedzi kilka zmiennych jednocześnie, rozmiar unii to rozmiar największego elementu. Jak zostanie ten fragment pamięci zinterpretowany, zależy od tego, do czego się odwołasz. Przykładowo:
union liczba{
short i16;
int i32;
char byte[4];
};
ma rozmiar 4 bajtów.
Jeśli przypiszesz do i32 jakąś liczbę, nadpiszesz całe 4 bajty. Możesz potem w prosty sposób odczytać poszczególne bajty z tego chara*. Po prostu program dany fragment pamięci będzie traktował tak, jak się do niego odwołasz. Jakbyś i32 nadał 0, a potem i16 np. 1345, to przy wypisaniu i32 też wypisałby 1345. Natomiast gdybyś do i32 przypisał np. 0xBBAADDCC, to przy wypisaniu i16 wypisałby 0xDDCC- 2 pierwsze bajty, tzn. najmniej znaczące, obecne komputery pracują na little-endian, byte[2] natomiast miałby wartość 0xAA.
Nie ma tam żadnej liczby przypadkowej, jak twierdzisz, a jeśli tak napisali w książce w której to wyczytałeś: autor się mylił lub po prostu nie wytłumaczył tego poprawnie (lub źle zrozumiałeś). Wcześniej przypisałeś coś do “metrow”, czyli double’a, czyli nadpisałeś całą unię (największy element). Skoro “mil” był intem, a przypisałeś chwilę wcześniej doubla, który ma zupełnie inną formę binarną, może się wydać że wypisał wartość losową. Tak faktycznie wypisał zinterpretowane 4 pierwsze bajty tego double jako int.
A czemu tak w tym drugim? Zaokrąglenie:
Bez nadpisywania metrów: 321.00000000000000000000
Z nadpisywaniem metrów: 321.00000000000568434189
Te 100 się zapisało akurat tam gdzieś, że robi taki ułamek. Poczytaj o sposobie zapisywania liczb zmiennoprzecinkowych.
Aha. Właśnie autor tej książki twierdził, że liczby są niszczone itd więc dlatego nie mogłem tego zrozumieć… Już mniej więcej to kapuje:) Poczytam sobie jeszcze dokładnie o tych liczbach zmiennoprzecinkowych… Dzięki za informacje:)