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!

 22
Author: M. Dudley, 2010-11-18

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.

 18
Author: Cheers and hth. - Alf,
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ędzy static_cast A reinterpret_cast.
 3
Author: Mike DeSimone,
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++).

 2
Author: Steve Jessop,
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));
 1
Author: Remy Lebeau,
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.

 0
Author: TonyK,
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.

 0
Author: MSalters,
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.

 -4
Author: Dylan Lukes,
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