28 września 2008

Problemy z typami danych cz I.

Notka będzie najeżona dużą dawką informacji. Zacznijmy!
Na początek tabelka rozmiarów podstawowych typów danych.
char      1
short 2
int 4 (na 32-bitowych komputerach!)
long long 8
Przyjrzyjmy się bliżej typowi int. Jego zakres to -231 ... 231-1. Warto przy tym wspomnieć, że liczba 231-1 (0x7fffffff) jest liczbą pierwszą. Zapamiętaj to! Znajomość dużych liczb pierwszych przyda Ci się przy kilku algorytmach.
W związku z tym, że mamy o jedną liczbę ujemną więcej niż dodatnią, rodzi się nasz pierwszy problem. Spójrzmy na następujący kod źródłowy programu C++:
int x = -231;
int y = -x;
pritnf("%d\n", y);
Pierwsza linijka nie stanowi żadnego kłopotu (nie licząc tego, że kompilator jej nie zaakceptuje). Druga linia rodzi pewien problem. Teoretycznie zmienna x powinna przyjąć wartość 231. Jednak ta liczba nie mieści się w zakresie inta. Pytanie: Jaką zatem wartość ma zmienna y?
Aby to ustalić spójrzmy jak w systemie binarnym zapisane są wybrane liczby całkowite.
 0    00000000 00000000 00000000 00000000
1 00000000 00000000 00000000 00000001
-1 11111111 11111111 11111111 11111111
-231 10000000 00000000 00000000 00000000
Prześledźmy działanie operatora unarnego "-":
- Negujemy wszystkie bity liczby
- Dodajemy do liczby jeden
Prześledźmy jak ten operator działa dla powyższych liczb. Zero poprawnie przechodzi na zero. Jeden przechodzi na minus jeden, a minus jeden na jeden. Natomiast -231 przechodzi na... -231. To nie koniec niespodzianek.

Przeanalizujmy następujący program:
printf("%d", 1 << 2);
printf("%d", 1 << 31);
printf("%d", 1 << 32);
Pierwsze dwie linie programu działają według naszych przypuszczeń. Pierwsza linijka wypisze na ekran "4", natomiast druga "-231". Natomiast z trzecią linijką jest kłopot o czym informuje nas już kompilator: "warning: left shift count >= width of type". Na ekranie zostanie wypisane "0". Ale spójrzmy jeszcze na to:
int x = 32;
printf("%d", 1 << x);
Program nie powinien się różnić od poprzedniego przykładu, a jednak. Po pierwsze kompilator nie informuje nas o zagrożeniu (kompilator "nie może wiedzieć" czy wartość x przekracza dozwolony zakres). Po drugie, na ekranie zostanie wypisana "1". Procesor bowiem weźmie resztę z dzielenia liczby x przez 32 i o taką liczbę bitów przesunie 1 w lewo. Trzeba o tym pamiętać i mieć to na uwadze.

W drugiej części przedstawię kolejne problemy, tym razem z własnymi strukturami danych.

2 komentarze:

Robert pisze...

To teraz tu piszesz ? :)

npb pisze...

Tak - obraziłem się na ostatni serwis na którym publikowałem :)