Kiedy casting zmienia bit wartości w C++?
Mam C++ unsigned int
, który faktycznie przechowuje podpisaną wartość. Chcę oddać tę zmienną signed int
, aby wartości unsigned i signed miały tę samą wartość binarną.
unsigned int lUnsigned = 0x80000001;
int lSigned1 = (int)lUnsigned; // Does lSigned == 0x80000001?
int lSigned2 = static_cast<int>(lUnsigned); // Does lSigned == 0x80000001?
int lSigned3 = reinterpret_cast<int>(lUnsigned); // Compiler didn't like this
Kiedy zmienić bity zmiennej w C++? Na przykład, Wiem, że rzut z {[3] } na float
zmieni bity, ponieważ int
jest dopełniaczem dwójkowym, a {[4] } zmiennoprzecinkowym. Ale co z innymi scenariuszami? Nie jestem jasny co do zasad tego w C++.
W sekcja 6.3.1.3 specyfikacji C99 mówi, że odlewanie z unsigned do signed integer jest zdefiniowane przez kompilator!
7 answers
Konwersja typu może
-
Zachowaj wartość koncepcyjną (bitpattern Może trzeba zmienić), lub
Zachowaj bitpattern (wartość koncepcyjna Może musi zostać zmieniona).
Jedyną obsadą C++, która gwarantuje zawsze utrzymanie bitpattern jest const_cast
.
A reinterpret_cast
jest, jak sama nazwa wskazuje, przeznaczony do zachowania bitpattern i po prostu reinterpretacji. Ale standard pozwala na wdrożenie bardzo dużo swobody w jak zaimplementować reinterpret_cast
. W niektórych przypadkach a {[1] } może zmienić bitpattern.
A dynamic_cast
ogólnie zmienia zarówno bitpattern, jak i wartość, ponieważ zazwyczaj zagłębia się w obiekt i zwraca wskaźnik/odniesienie do podrzędnego obiektu żądanego typu.
A static_cast
może zmieniać bitpattern zarówno dla liczb całkowitych, jak i wskaźników, ale , prawie wszystkie istniejące komputery używają reprezentacji podpisanych liczb całkowitych (zwanych dopełnieniem dwójki), gdzie static_cast
nie zmieni bitpattern. Dotyczące wskaźniki, wystarczy powiedzieć, że na przykład, gdy klasa bazowa jest nie-polimorficzna, a klasa pochodna jest polimorficzna, użycie static_cast
, aby przejść od wskaźnika do pochodnej do wskaźnika do bazy, lub odwrotnie, może zmienić bitpattern (jak widać porównując wskaźniki void*
). Teraz liczby całkowite...
Z bitami wartości n , typ unsigned integer ma wartości 2^n , w zakresie od 0 do 2^N -1 (włącznie).
Standard C++ gwarantuje, że każdy wynik typ jest owinięty do tego zakresu przez dodanie lub odjęcie odpowiedniej wielokrotności 2^n .
Tak to opisuje standard C; standard C++ mówi tylko, że operacje są modulo 2^n , co oznacza to samo.
Z dopełniaczem two podpisana wartość - x ma ten sam bitpattern co niepodpisana wartość - x+2^N . Czyli ten sam bitpattern co standard C++ gwarantuje, że uzyskasz poprzez konwersję - x na niepodpisany Typ o tym samym rozmiarze. To proste podstawy formy dopełniacza two, że jest to właśnie gwarancja, której szukasz. :-)
I prawie wszystkie istniejące komputery używają formy dopełniacza two.
Stąd w praktyce masz gwarancję niezmienionej bitpattern dla swoich przykładów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-18 21:02:41
Jeśli rzucisz z mniejszego podpisanego typu całki do większego podpisanego typu całki, kopie oryginalnego najbardziej znaczącego bitu (1
W przypadku liczby ujemnej) będą dodawane w razie potrzeby, aby zachować wartość liczby całkowitej.
Jeśli rzucisz wskaźnik obiektu na wskaźnik jednej z jego superklas, bity mogą się zmieniać, zwłaszcza jeśli istnieje wiele dziedziczeń lub wirtualnych superklas.
Pytasz o różnicę międzystatic_cast
A reinterpret_cast
.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-18 19:29:14
Jeśli twoja implementacja używa dopełniacza 2 dla typów signed integer, to rzutowanie z typów signed na unsigned integer o tej samej szerokości nie zmienia wzorca bitowego.
Przerzucanie z unsigned do signed może w teorii robić różne rzeczy, gdy wartość jest poza zakresem typu signed, ponieważ jest zdefiniowana w implementacji. Ale oczywistą rzeczą dla implementacji 2 jest użycie tego samego wzorca bitowego.
Jeśli twoja implementacja nie używa dopełniacza 2, a następnie rzutowanie pomiędzy wartościami signed i unsigned zmieni wzorzec bitowy, gdy podpisana wartość jest ujemna. Takie implementacje są jednak rzadkością (nie znam dokładnie żadnego zastosowania dopełnienia non-2 w kompilatorach C++).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-19 14:04:12
Używanie obsady w stylu C lub static_cast
, aby obsadzić {[2] } do signed int
może nadal pozwolić kompilatorowi przypisać pierwszą do drugiej bezpośrednio tak, jakby obsady nie zostały wykonane, a tym samym może zmienić bity, jeśli unsigned int
wartość jest większa niż to, co może pomieścić signed int
. A reinterpret_cast
powinno jednak działać, lub możesz wpisać-cast używając wskaźnika:
unsigned int lUnsigned = 0x80000001;
int lSigned1 = *((int*)&lUnsigned);
int lSigned2 = *(reinterpret_cast<int*>(&lUnsigned));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-18 20:10:30
Niepodpisana liczba całkowita jest zawsze tego samego rozmiaru co int. I każdy komputer na planecie używa teraz dopełnienia 2. Więc żaden z Twoich rzutów nie zmieni reprezentacji bitowej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-18 20:25:40
Szukasz int lSigned = reinterpret_cast<int&>(lUnsigned);
Nie chcesz reinterpretować wartości lUnsigned, chcesz reinterpretować obiekt lUnsigned. Stąd Obsada do typu odniesienia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-19 09:46:21
Casting jest tylko sposobem na nadpisanie sprawdzania typu, nie powinien właściwie modyfikować samych bitów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-18 19:00:57