2014-05-23 21 views
30

Do mojego zrozumienia, że ​​powinien dać błąd przepełnienia i kiedy piszę to tak:Dlaczego int.MaxValue - int.MinValue = -1?

public static void Main() 
{ 

    Console.WriteLine(int.MaxValue - int.MinValue); 
} 

to niepoprawnie dać mi błąd przepełnienia.

Jednakże:

public static void Main() 
{ 

    Console.WriteLine(test()); 
} 

public static Int32 test(int minimum = int.MinValue, int maximum = int.MaxValue) 
{ 
    return maximum - minimum; 
} 

wyświetli -1 Dlaczego to zrobić? Powinien rzucić błąd, ponieważ jest to wyraźnie przepełnienie!

+6

jestem jedyną osobą, która uczono, że 2147483647 - (-?. 2147483648) jest rzeczywiście 4294967295 – Aelphaeis

+0

tak 4294967295 nie jest int – harold

+0

Co byś oczekiwał, 2147483647 - 2147483648 dać ci? –

Odpowiedz

46

int.MaxValue - int.MinValue = wartość, której int nie może pomieścić. Tak więc liczba owija się z powrotem do -1.

Jest jak 2147483647 - (-) = 4294967295 2147483648 nie jest int

Int32.MinValue Field

Wartość tej stałej jest -2147483648; czyli heksadecymalnie 0x80000000.

I Int32.MaxValue Field

Wartość tej stałej jest 2147483647; czyli heksadecymalnie 0x7FFFFFFF.

Od MSDN

Gdy nastąpi całkowita przepełnienia, co się dzieje, zależy od kontekstu wykonanie , które mogą być sprawdzone lub niekontrolowany. W zaznaczonym kontekście generowany jest wyjątek OverflowExpert . W niezaznaczonym kontekście znaczące bity wyniku są odrzucane, a wykonywanie jest kontynuowane. W ten sposób C# daje wybór obsługi lub ignorowania przepełnienia.

+4

Edycja wyjaśnia, dziwię się, że domyślnie kompilator jest w niezaznaczonym stanie. – Aelphaeis

+0

@Aelphaeis: - Tak i dodać do niego Sprawdzone słowo kluczowe służy do jawnego włączenia sprawdzania przepełnienia dla operacji arytmetycznych i konwersji typu integralnego. –

+2

@Aelphaeis Jestem zaskoczony tak samo jak byłem pewien, że domyślne zostało sprawdzone. Ale [na MSDN, rzeczywiście "/ checked-' jest domyślnie] (http://msdn.microsoft.com/en-us/library/h25wtyxf.aspx). Wydaje się, że to zły wybór domyślny, ponieważ pozwala na ignorowanie błędów programowania w środowisku wykonawczym (i może mieć [implikacje dotyczące bezpieczeństwa?] (Http://cwe.mitre.org/data/definitions/190.html)). Zastanawiam się, dlaczego zespół C# dokonał takiego wyboru ... – LB2

13

Jest to spowodowane sprawdzaniem kodu przepełnienia podczas kompilacji. Linia

Console.WriteLine(int.MaxValue - int.MinValue); 

nie faktycznie błąd w czasie wykonywania, to byłoby proste write „-1”, ale ze względu na przepełnienie sprawdzanie masz błąd kompilacji „Operacja przelewa w czasie kompilacji w trybie zaznaczone”.

Aby obejść przepełnienia kompilacji kontroli w tym przypadku można zrobić:

  unchecked 
     { 
      Console.WriteLine(int.MaxValue - int.MinValue);     
     } 

Który będzie działać dobrze i wyjście „-1”

ustawienie
+0

Wywołanie funkcji @Michael podświetlanie sprawdzania przekroczenia czasu wykonywania to opcja na poziomie kompilacji. – Aidanapword

+1

Aby udzielić tej odpowiedzi, można również pokazać odwrotny efekt - polegający na umieszczeniu "sprawdzonego" wokół obliczeń w metodzie "test" - aby ten rzucił wyjątek, czyli to, co chciał OP. – ClickRick

2

Domyślny projekt poziomie, który kontroluje ten jest domyślnie "odznaczone". Możesz włączyć sprawdzanie przepełnienia, przechodząc do właściwości projektu, karty Build, przycisku Advanced. Wyskakujące okienko pozwala włączyć sprawdzanie przepełnienia. Narzędzie .NET Fiddle, z którym łączysz, wydaje się wykonywać dodatkowe analizy statyczne, które uniemożliwiają zobaczenie prawdziwego, nieoczekiwanego działania środowiska wykonawczego.(Błąd dotyczący pierwszego powyższego fragmentu kodu to "Operacja przepełnia się podczas kompilacji w trybie zaznaczonym." Nie widzisz błędu w czasie wykonywania.)

2

Myślę, że wykracza to nawet dalej niż przepełnienie.

jeśli spojrzeć na ten

Int64 max = Int32.MaxValue; 
Console.WriteLine(max.ToString("X16")); // 000000007FFFFFFF 
Int64 min = Int32.MinValue; 
Console.WriteLine(min.ToString("X")); //FFFFFFFF80000000 
Int64 subtract = max - min; 
Console.WriteLine(subtract.ToString("X16")); //00000000FFFFFFFF <- not an overflow since it's a 64 bit number 
Int32 neg = -1 
Console.WriteLine(neg.ToString("X")); //FFFFFFFF 

Tutaj widać, że jeśli po prostu odejmować wartości hex) w 2 uzupełnień masz numer, który jest -1 w liczbie 32 bitów. (Po trunkating wiodącą 0 za

2 uzupełniają arytmetyki może być bardzo zabawne http://en.wikipedia.org/wiki/Two „s_complement

Powiązane problemy