2010-06-02 10 views
32

Obsługa przepełnienia liczby całkowitej jest typowym zadaniem, ale jaki jest najlepszy sposób na obsłużenie go w języku C#? Czy jest jakiś cukier syntaktyczny, aby był prostszy niż w innych językach? Czy to naprawdę najlepszy sposób?Najlepszy sposób obsługi przepełnienia Integer w C#?

int x = foo(); 
int test = x * common; 
if(test/common != x) 
    Console.WriteLine("oh noes!"); 
else 
    Console.WriteLine("safe!"); 
+3

najlepszym sposobem jest, aby zapobiec w pierwszej kolejności –

+6

pewno, ale to już inna kwestia od prezentowanej tutaj.Obchodzenie się z nim i zapobieganie mu to oddzielne (związane oczywiście z) dyskusje. –

Odpowiedz

86

Nie potrzeba używać tego często, ale można użyć checked kluczowe:

int x = foo(); 
int test = checked(x * common); 

spowoduje wyjątek czasu wykonywania, jeśli przepełnienia. Od MSDN:

W sprawdzonej kontekście, jeśli wyrażenie tworzy wartość, która jest spoza zakresu typu docelowego, wynik zależy od czy wyrażenie jest stała lub nie stała. Stałe wyrażeń powodują błędy czasu kompilacji, a nieciągłe wyrażenia są oceniane w czasie wykonywania i powodują wyjątki.

I należy również podkreślić, że istnieje inny # kluczowe C unchecked, co oczywiście czyni przeciwieństwem checked i ignoruje przepełnienia. Możesz się zastanawiać, kiedy użyjesz unchecked, ponieważ wydaje się, że jest to domyślne zachowanie. Cóż, istnieje opcja kompilatora C#, która definiuje sposób obsługi wyrażeń spoza checked i unchecked: /checked. Możesz ustawić go w zaawansowanych ustawieniach kompilacji projektu.

Jeśli masz dużo wyrażeń, które wymagają sprawdzenia, najprościej byłoby ustawić opcję kompilacji /checked. Następnie każde wyrażenie, które się przepełni, o ile nie zostanie zapakowane w unchecked, spowoduje wyjątek środowiska wykonawczego.

+1

To wybitne. –

+3

Dlaczego domyślne zachowanie nie jest zaznaczone? Czy występują jakieś problemy z wydajnością dotyczące sprawdzania? – KFL

+1

@KFL "Ponieważ sprawdzenie przepełnienia wymaga czasu, użycie niezatwierdzonego kodu w sytuacjach, w których nie występuje niebezpieczeństwo przepełnienia, może poprawić wydajność .Jeśli jednak istnieje możliwość przepełnienia, należy użyć sprawdzonego środowiska." Zobacz http://msdn.microsoft.com/en-us/library/a569z7k8.aspx. Uważam także, że domyślne ustawienie nie jest zaznaczone, ponieważ jest podobne do zachowania C/C++. –

4

Zdarza się, że najprostszym sposobem jest najlepiej sposób. Nie mogę wymyślić lepszego sposobu, aby napisać to, co napisał, ale można go krótko:

int x = foo(); 

if ((x * common)/common != x) 
    Console.WriteLine("oh noes!"); 
else 
    Console.WriteLine("safe!"); 

pamiętać, że nie usunąć zmienną x ponieważ byłoby głupotą nazwać foo() trzy razy .

+0

Teraz zastanawiam się, czy kompilator kiedykolwiek zoptymalizuje to wyrażenie całkowicie? –

+1

USefull, chyba że planujesz użyć wyniku (x * często), w takim przypadku twój skrócenie wymagałoby dwukrotnego wykonania obliczeń ... – Cobusve

+3

Niebezpieczne, jeśli istnieje prawdopodobieństwo, że 'zwykły' może być 0 .. –

7

Najlepszym sposobem jest Micheal Said - użyj sprawdzonego słowa kluczowego. Można to zrobić tak:

int x = int.MaxValue; 
try 
{ 
    checked 
    { 
     int test = x * 2; 
     Console.WriteLine("No Overflow!"); 
    } 
} 
catch (OverflowException ex) 
{ 
    Console.WriteLine("Overflow Exception caught as: " + ex.ToString()); 
} 
+0

Musisz sformatować swój kod (wstaw 4 spacje przed nim, a strona automatycznie podniesie formatowanie i podświetlanie składni –

18

Spróbuj następujące

int x = foo(); 
try { 
    int test = checked (x * common); 
    Console.WriteLine("safe!"); 
} catch (OverflowException) { 
    Console.WriteLine("oh noes!"); 
} 
-1

stary wątek, ale po prostu wpadł na to. Nie chciałem używać wyjątków. Co skończyło się było:

long a = (long)b * (long)c; 
if(a>int.MaxValue || a<int.MinValue) 
    do whatever you want with the overflow 
return((int)a); 
+1

To nie zadziała. 'Int.MaxValue + 1' daje -2147483648 lub' int.MinValue '. tak więc' a' nigdy nie może być większe niż MaxValue lub mniejsze niż MinValue. Pomyśl o liczbach jak o następującej linii: '-2147483648, -2147483647, ... 0 ... 2147483646, 2147483647' kiedy przekroczysz maksimum wartość, płynie z powrotem do najmniejszego: –

+3

spóźniłeś się z faktem, że on/ona przekonwertował na długo przed sprawdzeniem w granicach int, więc to by działało tak długo, jak długo nie przepełni długo. – hammett

0

Więc wpadłem na to daleko po fakcie, i to przede wszystkim odpowiedział na moje pytanie, ale dla mojego konkretnego przypadku (w każdy inny zdarzenie ma takie same wymagania), I chciał niczego, co mogłoby przepełnić pozytywną wartość podpisanego int tylko osiedlenie w int.MaxValue:

int x = int.MaxValue - 3; 
int someval = foo(); 

try 
{ 
    x += someval; 
} 

catch (OverflowException) 
{ 
    x = int.MaxValue; 
} 
+0

Wyjątek nie zostanie rzucony chyba że kompilujesz z '' '/ checked''' lub użyjesz słowa kluczowego' '' checked''', prawda? –

Powiązane problemy