-2147483648 jest najmniejszą liczbą całkowitą dla typu liczb całkowitych z 32 bitami, ale wydaje się, że przepełni się w if(...)
zdaniu:
if (-2147483648 > 0)
std::cout << "true";
else
std::cout << "false";
Zostanie to wydrukowane true
podczas moich testów. Jeśli jednak użyjemy -2147483648 na liczbę całkowitą, wynik będzie inny:
if (int(-2147483648) > 0)
std::cout << "true";
else
std::cout << "false";
To zostanie wydrukowane false
.
Jestem zmieszany. Czy ktoś może wyjaśnić to?
Aktualizacja 02-05-2012:
Dzięki za komentarze, w moim kompilatorze rozmiar int to 4 bajty. Używam VC do prostych testów. Zmieniłem opis w moim pytaniu.
To wiele bardzo dobrych odpowiedzi w tym poście, AndreyT udzielił bardzo szczegółowego wyjaśnienia, w jaki sposób kompilator będzie zachowywał się na takich danych wejściowych i jak zaimplementowano tę minimalną liczbę całkowitą. Z drugiej strony qPCR4vir dał pewne powiązane „osobliwości” i sposób reprezentowania liczby całkowitej. Tak imponujące!
źródło
INT_MIN
z-9223372036854775808
, jeśliCHAR_BIT
jest 16. A nawetCHAR_BIT == 8
isizeof(int
== 4) `może pojawić się-9223372036854775807
, ponieważ C nie wymagają 2-Uzupełnienia liczb.Odpowiedzi:
-2147483648
nie jest „liczbą”. Język C ++ nie obsługuje ujemnych wartości literałów.-2147483648
jest właściwie wyrażeniem: dodatnią wartością dosłowną2147483648
z jednoznacznym-
operatorem przed nim. Wartość2147483648
jest najwyraźniej za duża dla pozytywnej stronyint
zasięgu na twojej platformie. Gdyby typlong int
miał większy zasięg na twojej platformie, kompilator musiałby automatycznie założyć, że2147483648
ma onlong int
typ. (W C ++ 11 kompilator musiałby również wziąć pod uwagęlong long int
typ.) Sprawiłoby to, że kompilator oceniałby-2147483648
w domenie większego typu, a wynik byłby ujemny, jak można by się spodziewać.Jednak najwyraźniej w twoim przypadku zasięg
long int
jest taki sam jak zasięgint
i ogólnie nie ma typu całkowitego o większym zasięgu niżint
na twojej platformie. To formalnie oznacza, że dodatnia stała2147483648
przepełnia wszystkie dostępne typy liczb całkowitych ze znakiem, co z kolei oznacza, że zachowanie twojego programu jest niezdefiniowane. (To trochę dziwne, że specyfikacja języka wybiera w takich przypadkach niezdefiniowane zachowanie, zamiast wymagać komunikatu diagnostycznego, ale tak właśnie jest.)W praktyce, biorąc pod uwagę, że zachowanie jest niezdefiniowane,
2147483648
może zostać zinterpretowane jako pewna ujemna wartość zależna od implementacji, która zmienia się w dodatnią po-
zastosowaniu do niej jednostronnej wartości . Alternatywnie, niektóre implementacje mogą podjąć decyzję o próbie użycia niepodpisanych typów do przedstawienia wartości (na przykład w kompilatorach C89 / 90 było to wymaganeunsigned long int
, ale nie w C99 lub C ++). Implementacje mogą robić wszystko, ponieważ i tak zachowanie jest niezdefiniowane.Na marginesie, jest to powód, dla którego stałe takie
INT_MIN
są zwykle definiowane jakozamiast pozornie prostszego
Ten ostatni nie działałby zgodnie z przeznaczeniem.
źródło
#define INT_MIN (-2147483647 - 1)
.int
. Implementacja OP może nie mieć typu 64-bitowego.-1.0
jest to analizowane jako podwójna ujemna wartość, prawda?unsigned long int
w tym kontekście, ale w C99 to zezwolenie zostało usunięte. Nienaprawione literały w C i C ++ muszą mieć podpisane typy. Jeśli zobaczysz tutaj niepodpisany typ, w którym zadziała podpisany, oznacza to, że Twój kompilator jest uszkodzony. Jeśli zobaczysz tutaj niepodpisany typ, gdy żaden podpisany typ nie zadziała, to jest to tylko szczególny przejaw niezdefiniowanego zachowania.Kompilator (VC2012) promuje do „minimalnych” liczb całkowitych, które mogą przechowywać wartości. W pierwszym przypadku
signed int
(ilong int
) nie może (przed zastosowaniem znaku), aleunsigned int
może:2147483648
maunsigned int
???? rodzaj. W drugiej wymuszaszint
zunsigned
.Oto powiązane „osobliwości”:
Standard C ++ 11 :
…
…
I to są zasady promocji dla liczb całkowitych w standardzie.
źródło
int
,long int
,unsigned long int
do reprezentowania unsuffixed stałe dziesiętne. To był jedyny język, który pozwalał używać niepodpisanych typów dla niefiksowanych stałych dziesiętnych. W C ++ 98 było toint
lublong int
. Niedozwolone typy bez znaku. Ani C (począwszy od C99), ani C ++ nie pozwala kompilatorowi na używanie typów niepodpisanych w tym kontekście. Twój kompilator może oczywiście używać typów niepodpisanych, jeśli żaden z podpisanych nie działa, ale nadal jest to tylko szczególny przejaw nieokreślonego zachowania.int
lublong int
do reprezentowania2147483648
. AFAIK, zarówno w VC2012, jakint
ilong int
32-bitowym. Oznacza to, że w VC2012 dosłowność2147483648
powinna prowadzić do nieokreślonego zachowania . Gdy zachowanie jest niezdefiniowane, kompilator może robić wszystko. Oznaczałoby to, że VC2012 nie jest uszkodzony. Po prostu wydał mylący komunikat diagnostyczny. Zamiast powiedzieć ci, że zachowanie jest całkowicie nieokreślone, postanowił użyć typu bez znaku.long
i nie jest wymagany do wydania komunikatu diagnostycznego? To wydawałoby się zepsute.Krótko mówiąc,
2147483648
przepełnia się-2147483648
i(-(-2147483648) > 0)
jesttrue
.Tak to
2147483648
wygląda w systemie binarnym.Ponadto w przypadku podpisanych obliczeń binarnych najbardziej znaczącym bitem („MSB”) jest bit znaku. To pytanie może pomóc wyjaśnić dlaczego.
źródło
Ponieważ w
-2147483648
rzeczywistości zastosowano do niego2147483648
negację (-
), liczba nie jest taka, jak można się spodziewać. W rzeczywistości jest to odpowiednik tego pseudokodu:operator -(2147483648)
Teraz, zakładając, że twój kompilator ma wartość
sizeof(int)
równą4
iCHAR_BIT
jest zdefiniowany jako8
, to spowoduje, że2147483648
przepełnienie będzie maksymalną podpisaną wartością liczby całkowitej (2147483647
). Więc jaka jest maksymalna plus jedna? Pozwala to sprawdzić z 4-bitową liczbą całkowitą komplement 2s.Czekać! 8 przepełnia liczbę całkowitą! Co robimy? Użyj jego niepodpisanej reprezentacji
1000
i interpretuj bity jako liczbę całkowitą ze znakiem. Ta reprezentacja pozostawia nam-8
zastosowanie negacji dopełniacza 2s8
, co, jak wszyscy wiemy, jest większe niż0
.Właśnie dlatego
<limits.h>
(i<climits>
) zwykle definiuje sięINT_MIN
jako((-2147483647) - 1)
- tak, że maksymalna liczba całkowita ze znakiem (0x7FFFFFFF
) jest negowana (0x80000001
), a następnie zmniejszana (0x80000000
).źródło
-8
jest nadal-8
.-(8)
która w C ++ jest taka sama jak-8
- jest to negacja zastosowana do literału, a nie negatywna literał. Dosłowne jest to8
, że nie pasuje do 4-bitowej liczby całkowitej ze znakiem, więc musi być bez znaku. Wzór jest1000
. Jak dotąd twoja odpowiedź jest prawidłowa. Negacja uzupełnienia dwóch1000
w 4 bitach jest taka1000
, że nie ma znaczenia, czy jest podpisana czy niepodpisana. Twoja odpowiedź mówi „interpretuj bity jako liczbę całkowitą ze znakiem”, która tworzy wartość-8
po negacji dopełniacza dwóch, tak jak przed negacją.8
. Stosuje się negację (moduł 16), co daje ostateczną odpowiedź na8
. Kodowanie to wciąż 1000, ale wartość jest inna, ponieważ wybrano typ bez znaku.