2010-10-16 11 views
14

Ci sono molte domande sul rilevamento dell'overflow dei numeri interi PRIMA dell'effettiva aggiunta/sottostringa a causa del possibile undefined behavior. Quindi, la mia domanda èOverflow intero e comportamento indefinito

Perché produrrà questo undefined behavior in primo luogo?

posso pensare 2 cause:

1) Un processore che genera un'eccezione in questo caso. Certo, può essere disattivato e molto probabilmente un CRT ben scritto lo farà.

2) Un processore che utilizza altre rappresentazioni binarie di numeri (1 complemento? Base 10?). In tal caso il comportamento indefinito si manifesterà come risultato diverso (ma non si bloccherà!). Bene, potremmo vivere con quello.

Quindi, perché qualcuno dovrebbe evitare di causarlo? Mi sto perdendo qualcosa?

+1

Link obbligatorio: http://blog.regehr.org/archives/213 –

+0

correlati: http://stackoverflow.com/questions/18195715/why-is-unsigned-integer-overflow-defined-behavior-but- sign-integer-overflow-is –

risposta

11

Sebbene maggior CPU moderni usano complemento a 2, e risultati integer overflow nei prevedibile avvolgente modulo, questo non è affatto universale - a mantenere il linguaggio sufficientemente generale che può essere utilizzato su più ampia gamma di architetture è meglio specificare che l'overflow integer è UB.

+1

Qualsiasi CPU è complementare a due se il compilatore semplicemente omette di generare gli opcode aritmetici firmati inutili e utilizza quelli non firmati per entrambi i tipi con segno e senza segno. Questo può comportare minori perdite di prestazioni quando si fanno paragoni (per esempio, ora 'x <-1' richiede 2 confronti a livello macchina invece di 1), ma io per primo preferirei che fosse così. –

+0

@R: il complemento a 2 non è l'unico problema - ad es. alcune CPU (DSP, ad esempio) hanno aritmetica saturante piuttosto che aritmetica modulo. –

+1

L'aritmetica modulare è necessaria per supportare comunque i tipi non firmati ... se la tua macchina non ce l'ha, suppongo che tu debba implementarla. Un approccio potrebbe essere utilizzare il bit superiore come padding e azzerarlo dopo ogni operazione. –

4

I bit undefined behavior nella specifica implicano l'ottimizzazione del compilatore. Per esempio:

if (a > 0 && b > 0) { 
    if (a + b <= 0) { 
     // this branch may be optimized out by compiler 
    } else { 
     // this branch will always run 
    } 
} 

moderna compilatori C non sono così semplici, è fare un sacco di indovinare e ottimizzazione.

+0

Buon punto, ma questo significa solo che il compilatore C non ti aiuterà a rilevarlo. – ruslik

+0

un altro punto: mentre il compilatore sarebbe in grado di rilevare questa condizione aritmetica, alcune operazioni di bit sarebbero in grado di ingannarlo in modo che la condizione non venga ottimizzata. Inoltre, come suggerito da nategoose, potremmo semplicemente dichiarare la somma come 'volatile'. – ruslik

+3

Questo non è un uso valido della parola chiave 'volatile'. Se funziona, è il risultato di un'implementazione specifica, un comportamento non specificato. Cioè è ancora un comportamento indefinito. –

0

Penso che la tua ipotesi 1) che questo possa essere disattivato per un determinato processore è stato falso su almeno un'architettura storica importante, il CDC, se la mia memoria è corretta.

+0

Questo è davvero vecchio. Preferirei gestire questi casi con '# ifdef'. – ruslik

+0

@ruslik: La domanda non è ** come ** per gestire questo, '# ifdef 'è solo un modo per evitare UB. Ma vedi, come dici tu stesso, che gestiresti questo in qualche modo. La compatibilità con le versioni precedenti di –

+0

ha i suoi limiti. In questo caso preferirei piuttosto scrivere buggy, ma codice semplice. – ruslik

11

Mentre il motivo storico con overflow firmato era specificato come comportamento non definito erano probabilmente queste false rappresentazioni legacy (un complemento/segno di magnitudo) e interruzioni di overflow, la ragione moderna per cui il comportamento indefinito rimane è l'ottimizzazione. Come accennato a J-16 SDiZ, il fatto che l'overflow firmato sia un comportamento indefinito consente al compilatore di ottimizzare alcuni condizionali la cui verità algebrica (ma non necessariamente verità a livello di rappresentazione) è già stabilita da un ramo precedente. Può anche consentire al compilatore di semplificare algebricamente alcune espressioni (in particolare quelle che coinvolgono moltiplicazione o divisione) in modi che potrebbero dare risultati diversi rispetto all'ordine di valutazione originariamente scritto se una sottoespressione contiene un overflow, poiché il compilatore può supporre che l'overflow non succede con gli operandi che gli hai dato.

L'altro enorme esempio di comportamento non definito allo scopo di consentire l'ottimizzazione è le regole di aliasing.

+3

uvetta isterica dern –

+0

Si potrebbe sostenere che gli interi senza segno dovrebbero comportarsi in modo coerente, perché perché non assumere che un + b> = a e a + b> = b per interi senza segno nell'ottimizzatore (simile alla conclusione di + b> 0 per un > 0 e b> 0 nell'esempio di J-16 SDiZ per interi con segno)? Ai miei occhi questo è più di una stranezza nelle specifiche C. – nucleon

+1

@nucleon: I tipi senza segno sono * specificati come aritmetica modulare * (dove non valgono quelle equivalenze algebriche delle disuguaglianze). I tipi firmati non lo sono. Se ti piace chiamarlo una stranezza in C, così sia, ma è così che è e non è davvero qualcosa che puoi cambiare. –

Problemi correlati