signed int x= -5;
unsigned int y=x;
jaka jest wartość y? i jak?Wartości niepodpisane i podpisane w C (jaka jest wydajność)
signed int x= -5;
unsigned int y=x;
jaka jest wartość y? i jak?Wartości niepodpisane i podpisane w C (jaka jest wydajność)
Y = 0xfffffffb jest binarna reprezentacja -5 (uzupełnienie dwójkowe)
Czy mógłbyś wyjaśnić więcej ... –
Wynik nie zależy od "reprezentacji binarnej". Wynik jest podyktowany wymaganiami standardu językowego. W tym przypadku standard jest dość wyraźny. – AnT
@AndreyT. Aby być sprawiedliwym, chociaż nie jest to powiedziane w ten sposób, to z pewnością prawdą jest, że dopełnienie 2 -> unsigned conversion daje ten sam wzorzec bitowy (myślę, że standard C++ wspomina o tym na marginesie, nie pamięta, czy standard C). Opis Philiberta jest równoznaczny z definicją zawartą w standardzie: możesz konwertować podpis -> unsigned przez wyliczenie uzupełnienia 2 do podpisanej wartości, a następnie odczytanie jej jako wartości unsigned. Nigdy nie powiedział, że tak właśnie działa implementacja (chociaż bez wątpienia implementacje uzupełnień 2). –
Zależy to od wartości maksymalnej unsigned int
. Zazwyczaj unsigned int
jest 32-bitowy długości, tak UINT_MAX
wynosi 2 − 1. Standard C (§ 6.3.1.3/2) wymaga podpisany → unsigned konwersja może być wykonywane jak
przeciwnym razie, jeśli nowy typ jest niepodpisany, wartość jest konwertowana przez wielokrotne dodawanie lub odejmowanie o jeden więcej niż maksymalna wartość, która może być reprezentowana w nowym typie, dopóki wartość nie znajdzie się w zakresie nowego typu.
Tak więc Y = X + ((2 − 1) + 1) = 2 − 5 = 4294967291.
na platformie 2's complement, które są w większości implementacji w dzisiejszych czasach, y
jest również taki sam jak uzupełnienie do 2-go uzupełnienia x
.
-5 ~ = 5 + 1 = 0xFFFFFFFA + 1 = 0xFFFFFFFB = 4294967291.
Wartość y
jest UINT_MAX - 5 + 1
tj UINT_MAX - 4
.
Po przekonwertowaniu liczby całkowitej ze znakiem na typ bez znaku, wartość jest zmniejszana modulo 2^N, gdzie N jest liczbą bitów tworzących wartość w typie bez znaku. Dotyczy to zarówno wartości liczbowych ujemnych, jak i dodatnich.
Jeśli konwersja podpisanych typu do unsigned o tej samej wielkości, powyższe oznacza, że korzystne wartości ze znakiem pozostają bez zmian (+5
przechodzi na 5
, na przykład), a wartości ujemne dodane do MAX + 1
, gdzie MAX
jest maksymalna wartość niepodpisanego typu (-5
zostaje przekształcona na MAX + 1 - 5
).
od standardu C99:
6.3.1.3 Signed całkowitymi bez znaku i
- Jeśli wartości z liczby całkowitej typu przekształca się w inny rodzaj całkowitej inny niż _Bool jeśli wartość może być reprezentowany przez nowy typ, pozostaje niezmieniony.
- przeciwnym razie, jeżeli nowy typ jest podpisany wartość jest przekształcany przez kilkakrotnie dodając lub odjęcie o jeden więcej niż wartość maksymalna, która może być reprezentowana w nowego typu do wartości w zakresie nowego typu . 49)
49) Zasady opisują arytmetycznie wartość matematyczną, a nie wartość danego typu wyrażenia.
Będziesz więc skutecznie sprawdzać, y = x + UINT_MAX + 1
.
Po prostu oznacza to, że reprezentacja uzupełnienia dwójki jest używana jako niezmieniona jako liczba całkowita bez znaku, co czyni ją bardzo szybką na większości współczesnych komputerów, ponieważ używają one dwójki-uzupełnienia dla liczb całkowitych ze znakiem.
Podpisane wartości są zwykle przechowywane jako coś, co nazywa two's complement: numery
uzupełnienie dwójkowe są sposobem kodowania liczb ujemnych w zwykłym binarny tak, że dodatek nadal działa. Dodawanie -1 + 1 powinno być równe 0, ale zwykłe dodawanie daje wynik 2 lub -2, chyba że operacja zwraca szczególną uwagę na bit znaku i zamiast tego wykonuje odejmowanie. Uzupełnienie dwóch daje prawidłową sumę bez tego dodatkowego kroku.
Oznacza to, że rzeczywisty reprezentację liczb -5 4294967291 w pamięci (na słowa 32 bitów) są identyczne, na przykład: 0xFFFFFFFB
lub 0b11111111111111111111111111111011
. kiedy tak zrobić:
unsigned int y = x;
Zawartość X jest dosłownej tj bitowe do y
. Oznacza to, że jeśli przejrzysz surowe wartości w pamięci x
i y
, będą one identyczne. Jeśli jednak zrobić:
unsigned long long y1 = x;
wartość x
zostanie przedłużony logowania przed konwertowane do unsigned long long. W typowym przypadku, gdy długo trwa 64 bity, oznacza to, że y1
jest równy 0xFFFFFFFFFFFFFFFB
.
Należy pamiętać, co dzieje się podczas rzutowania na większy typ. Podpisana wartość rzucana do większej podpisanej wartości zostanie przedłużona znakiem. Tak się nie stanie, jeżeli wartość źródłowa jest niepodpisany, np .:
unsigned int z = y + 5;
long long z1 = (long long)x + 5; // sign extended since x is signed
long long z2 = (long long)y + 5; // not sign extended since y is unsigned
z
i z1
będzie równy 0, ale z2
nie będzie. Można temu zaradzić poprzez odlanie wartość podpisanej przed rozszerzając go:
long long z3 = (long long)(signed int)y + 5;
lub analogicznie jeśli nie chcą przedłużenia znak wystąpić:
long long z4 = (long long)(unsigned int)x;
Ale pytanie dotyczy konwersji na * niepodpisany * typ. Jednak w odpowiedzi podajesz konwersje tylko do * podpisanych * typów. – AnT
Błagam, by się różnił, choć skupiam się nieco na konwersjach na typy podpisane, bo tam są smoki. Nie sądzę też, że moja odpowiedź zasługuje na pochwałę, ale jestem stronniczy. –
+1: dla "uzupełnienia dwójki", nawet jeśli w rzeczywistości wymijające sformułowanie C99 daje definicję, która działałaby również z kompilatorem, który użyłby powiedzmy BCD.Zastanawiam się, czy taki kompilator C istnieje mimo to, dopóki nie udowodniłem, że jest błędny. Uważam, że wszystkie obecnie istniejące kompilatory C używają uzupełnienia dwójkowego. – kriss
Kiedy próbowałem, co widziałeś? –
@KennyTM, nie zdefiniowano implementacji; rzutowanie z unsigned int na podpisany int, który nie może go reprezentować, to zdefiniowanie implementacji, ale na odwrót (signed -> unsigned) jest dobrze zdefiniowane. – bdonlan
@bdonlan: 'UINT_MAX' * jest * zdefiniowana implementacja. – kennytm