2010-01-13 1 views
49

Ho avuto questa strana esperienza con il problema numero 10 su Project Euler (ottimo sito a proposito). L'incarico consisteva nel calcolare la somma di tutti i numeri primi inferiori a due milioni.Nessuna eccezione di overflow per int in C#?

Ho usato un int per la somma e il mio algoritmo ha prodotto una risposta, ma quando l'ho incollato per verificare la risposta, era sbagliato.

Si è scoperto che il risultato era troppo grande per rientrare in un int, ma ciò non causerebbe un errore di overflow o qualcosa del genere? Invece, ha appena restituito un valore molto lontano dalla risposta reale.

Quando ho cambiato il tipo a lungo, tutto era hunky dory.

+5

Vuoi davvero ogni operazione intero per verificare la presenza di overflow? –

+4

Bene, in questo caso particolare mi avrebbe risparmiato un po 'di tempo;) – erikric

+1

In questo caso, sì. La stragrande maggioranza delle operazioni non può però traboccare. Sarebbe interessante se il compilatore potesse provarlo e disabilitare il controllo come risultato, ma dubito fortemente che lo faccia. – Thorarin

risposta

73

Le operazioni di C# integer non generano eccezioni in caso di overflow di default. È possibile ottenere che tramite le impostazioni di progetto, o facendo il calcolo checked:

int result = checked(largeInt + otherLargeInt); 

Ora l'operazione sarà buttare.

L'opposto è unchecked, che rende esplicitamente deselezionata qualsiasi operazione. Ovviamente, questo ha senso solo quando le operazioni di controllo sono abilitate nelle impostazioni del progetto.

+0

A meno che non siate in modalità di debug, dove penso che le operazioni int siano selezionate di default. – Ant

+5

No. Ho funzionato in modalità di debug quando ciò si è verificato. – erikric

+0

Oh. Sono corretto. Ero sicuro che i progetti Project Euler mi parlassero degli overflow in modalità debug.:/ – Ant

19

In C# un OverflowException non viene generato (in VB viene generata l'eccezione per impostazione predefinita).

Per ottenere l'excpetion bisogna inserire il codice in un checked contesto:

byte value = 241; 
checked 
{ 
    try 
    { 
     sbyte newValue = (sbyte) value; 
     Console.WriteLine("Converted the {0} value {1} to the {2} value {3}.", 
      value.GetType().Name, value, 
      newValue.GetType().Name, newValue); 
    } 
    catch (OverflowException) 
    { 
     Console.WriteLine("Exception: {0} > {1}.", value, SByte.MaxValue); 
    } 
}  

MSDN spiega più in dettaglio:

Per l'aritmetica, la fusione, o conversione operazione da buttare a OverflowException, l'operazione deve verificarsi in un contesto controllato. Con , le operazioni aritmetiche e gli overflow in Visual Basic vengono controllati; in C#, non lo sono. Se l'operazione si verifica in un contesto deselezionato, il risultato viene troncato scartando eventuali bit di ordine superiore che non rientrano nel tipo di destinazione .

6

Ho già aggiunto un CMT, ma è forse interessante per alcuni di voi:

msdn ci dice:

Integer overflow aritmetico sia genera OverflowException o scarta la maggior parte bit significativi di il risultato

ma

Overflow aritmetico decimale sempre genera una OverflowException.

anche

Quando si verifica integer overflow, cosa succede dipende dal contesto di esecuzione , che può essere controllato o deselezionata. In un contesto controllato, viene lanciata una OverflowException . In un contesto non controllato , la maggior parte dei bit significativi del risultato è scartata e l'esecuzione continua. Così, C# ti dà la scelta di gestendo o ignorando l'overflow.

+0

Il che ha senso, dal momento che i decimali sono usati principalmente per calcoli valutari o scientifici, e probabilmente preferiresti farli lanciare e poi fallire silenziosamente. – Snellface

6

Per impostazione predefinita, C# non controlla l'overflow aritmetico sugli interi. È possibile modificare questo con /checkedcompiler option o attivando "Verifica aritmetica di overflow/underflow" in Visual Studio (proprietà del progetto - Build - Avanzate).

È possibile utilizzare checked and unchecked keywords per sovrascrivere il valore predefinito caso per caso. Se ti affidi al controllo che si svolge in un pezzo di codice, abilitarlo esplicitamente usando checked sarebbe una buona idea.

int j = checked(i * 2); 

checked 
{ 
    int j = i * 2; 
    // Do more stuff 
} 

Nota che le operazioni in virgola mobile Non gettare un OverflowException, e le operazioni di decimali gettano sempre OverflowException. Vedi anche C# operators.

9

È perché, per impostazione predefinita, C# non genera eccezioni per l'overflow dei numeri interi e per l'underflow. Ci sono un paio di cose che puoi fare qui.

Opzione 1

Devi abilitare l'eccezione per essere gettato da andare a Progetto => Proprietà => scheda Costruisci => Avanzate => verificare la presenza di overflow aritmetico underflow. (Assicuratevi selezionare l'opzione)

enter image description here

Assicurati di spuntare l'opzione

Opzione 2

Utilizzare un blocco controllato e un'eccezione di overflow per gestire la situazione. Un frammento di codice di esempio sarebbe

 try 
     { 
      checked 
      { 
       int y = 1000000000; 
       short x = (short)y; 
      } 
     } 
     catch (OverflowException ex) 
     { 
      MessageBox.Show("Overflow"); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show("Error"); 
     } 

Spero che questo vi aiuterà a ... :)

+2

L'opzione 1 è il punto cruciale che molte persone non conoscono. Ottieni il mio +1. – RBT