2010-06-02 14 views
32

La gestione di overflow di numeri interi è un'operazione comune, ma qual è il modo migliore di gestirli in C#? C'è dello zucchero sintattico per renderlo più semplice rispetto ad altre lingue? O è davvero il modo migliore?Il modo migliore per gestire l'overflow integer in C#?

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

modo migliore è quello di evitare in primo luogo –

+6

Certo, ma questa è una domanda diversa da quella qui presentata.Gestirlo e prevenirlo sono discussioni separate (correlate ovviamente). –

risposta

86

non ho bisogno di usare questo spesso, ma è possibile utilizzare la parola chiave checked:

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

si tradurrà in un'eccezione di runtime se overflow. Da MSDN:

In un contesto controllato, se un'espressione produce un valore che è fuori del campo del tipo di destinazione, il risultato dipende se l'espressione è costante e non costante. Le espressioni costanti causano errori di compilazione, mentre le espressioni non costanti vengono valutate in fase di esecuzione e generano eccezioni.

Vorrei anche sottolineare che c'è un altro C# parola chiave, unchecked, che ovviamente fa il contrario di checked e ignora overflow. Potresti chiederti quando useresti mai unchecked dal momento che sembra essere il comportamento predefinito. Bene, c'è un'opzione del compilatore C# che definisce come vengono gestite le espressioni al di fuori di checked e unchecked: /checked. Puoi impostarlo nelle impostazioni di generazione avanzate del tuo progetto.

Se si dispone di molte espressioni da controllare, la cosa più semplice da fare sarebbe in realtà impostare l'opzione di creazione /checked. Quindi qualsiasi espressione che trabocca, a meno che non sia stata completata in unchecked, comporterebbe un'eccezione di runtime.

+1

È eccezionale. –

+3

Perché il comportamento predefinito è deselezionato? C'è qualche problema di prestazioni nell'uso controllato? – KFL

+1

@ KFL "Poiché il controllo dell'overflow richiede tempo, l'uso del codice non controllato in situazioni in cui non vi è il rischio di overflow può migliorare le prestazioni, tuttavia, se l'overflow è una possibilità, è necessario utilizzare un ambiente controllato." Vedi http://msdn.microsoft.com/en-us/library/a569z7k8.aspx. Credo anche che il valore predefinito sia deselezionato perché è parallelo al comportamento C/C++. –

4

A volte, il modo più semplice è il modo migliore . Non riesco a pensare un modo migliore per scrivere quello che hai scritto, ma si può brevemente per:

int x = foo(); 

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

Nota che non ho rimuovere la variabile x perché sarebbe sciocco a chiamare i foo() tre volte .

+0

Ora mi chiedo se il compilatore possa mai ottimizzare quell'espressione completamente? –

+1

USefull, a meno che, ovviamente, non si stia pianificando di utilizzare il risultato (x * comune), in tal caso il proprio accorciamento richiederebbe il calcolo due volte ... – Cobusve

+3

Pericoloso se esiste la possibilità che 'common' possa essere 0 .. –

7

Il modo migliore è come Micheal ha detto: utilizzare Parola chiave verificata. questo può essere fatto come:

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

È necessario formattare il codice (inserire 4 spazi prima e il sito acquisirà automaticamente la formattazione e l'evidenziazione della sintassi. –

18

provare il vecchio filo seguente

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

, ma ho appena imbattuto in questo. Non volevo usare le eccezioni. Quello che ho finito con era:

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

Questo non funzionerà. "Int.MaxValue + 1' fornisce -2147483648 o" int.MinValue '. quindi' a' non può mai essere più grande di MaxValue o inferiore a MinValue. Pensa ai numeri come ad una linea come questa: '-2147483648, -2147483647, ... 0 ... 2147483646, 2147483647' quando superi il limite massimo valore, torna al più piccolo. –

+3

ti sei perso il fatto che lui/lei ha convertito molto tempo prima di controllare i limiti dell'int, quindi avrebbe funzionato fino a quando non ha superato il lungo. – hammett

0

Così, mi sono imbattuto in questo punto dopo il fatto, ed è in gran parte risposto alla mia domanda, ma per il mio caso particolare (in chiunque evento altro ha gli stessi requisiti), I voluto nulla che possa traboccare il valore positivo di un int firmato a stabilirsi proprio in int.MaxValue:

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

try 
{ 
    x += someval; 
} 

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

L'eccezione non veniva lanciata a meno che non si compili con '' '/ checked''', o si usi la parola chiave' 'checked''', corretta? –

Problemi correlati