Domanda

Ho letto un po 'in C specifiche che non firmate variabili (in particolare Short senza segno int) esegui alcuni cosiddetti arrotolare su intero overflow, anche se non sono riuscito a trovare nulla su variabili firmate tranne che me ne sono andato comportamento indefinito.

Il mio professore mi ha detto che anche i loro valori vengono avvolti (forse intendeva solo GCC). Pensavo che i bit fossero appena stati troncati e i pezzi che ho lasciato mi hanno dato un valore strano!

Ciò che è avvolgente e come è diverso dal solo troncamento di pezzi.

È stato utile?

Soluzione

Le variabili interi firmate non hanno un comportamento avvolgente nella lingua C. L'overflow intero firmato durante i calcoli aritmetici produce comportamento indefinito. Nota BTW che il compilatore GCC che hai menzionato è noto per l'implementazione Semantica di overflow rigorosa In ottimizzazioni, il che significa che sfrutta la libertà fornita da tali situazioni di comportamento non definite: il compilatore GCC presuppone che i valori interi firmati non si avvolgano mai. Ciò significa che GCC in realtà è uno dei compilatori in cui tu non può Affidati al comportamento avvolgente dei tipi interi firmati.

Ad esempio, il compilatore GCC può supporre che per variabile int i la seguente condizione

if (i > 0 && i + 1 > 0)

è equivalente a un semplice

if (i > 0)

Questo è esattamente cosa Semantica di overflow rigorosa significa.

Tipi di interi non firmati implementano aritmetico modulo. Il modulo è uguale 2^N dove N è il numero di bit nella rappresentazione del valore del tipo. Per questo motivo i tipi di interi non firmati sembrano effettivamente avvolgere su Overflow.

Tuttavia, la lingua C non esegue mai calcoli aritmetici in domini più piccoli di quelli di int/unsigned int. Tipo unsigned short int che menzionate nella tua domanda verrà in genere promosso per digitare int nelle espressioni prima dell'inizio di qualsiasi calcolo (supponendo che l'intervallo di unsigned short si adatta alla gamma di int). Il che significa che 1) i calcoli con unsigned short int sarà preformato nel dominio di int, con il trabocco che si verifica quando int traboccanti, 2) L'overflow durante tali calcoli porterà a comportamenti indefiniti, non a un comportamento avvolgente.

Ad esempio, questo codice produce un avvolgimento intorno

unsigned i = USHRT_MAX;
i *= INT_MAX; /* <- unsigned arithmetic, overflows, wraps around */

mentre questo codice

unsigned short i = USHRT_MAX;
i *= INT_MAX; /* <- signed arithmetic, overflows, produces undefined behavior */

porta a comportamenti indefiniti.

Se no int Overflow accade e il risultato viene convertito in un unsigned short int Tipo, viene nuovamente ridotto dal modulo 2^N, che apparirà come se il valore fosse avvolto.

Altri suggerimenti

Immagina di avere un tipo di dati largo solo 3 bit. Ciò ti consente di rappresentare 8 valori distinti, da 0 a 7. Se aggiungi 1 a 7, "si avvolgerai" a 0, perché non hai abbastanza bit per rappresentare il valore 8 (1000).

Questo comportamento è ben definito per i tipi non firmati. è non Ben definito per i tipi firmati, perché ci sono più metodi per rappresentare valori firmati e il risultato di un overflow verrà interpretato in modo diverso in base a quel metodo.

Magnitudine dei segni: il bit più alto rappresenta il segno; 0 per positivo, 1 per negativo. Se il mio tipo è di nuovo largo tre bit, allora posso rappresentare i valori firmati come segue:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -0
101  = -1
110  = -2
111  = -3

Dato che un bit viene preso per il segno, ho solo due bit per codificare un valore da 0 a 3. Se aggiungo 1 a 3, traboccerò con -0 come risultato. Sì, ci sono due rappresentazioni per 0, una positiva e una negativa. Non incontrerai così spesso la rappresentazione della magnitudine dei segni.

Completamento uno: il valore negativo è il bitwise-inverso del valore positivo. Ancora una volta, usando il tipo a tre bit:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -3
101  = -2
110  = -1 
111  = -0

Ho tre bit per codificare i miei valori, ma l'intervallo è [-3, 3]. Se aggiungo da 1 a 3, traboccerò con -3 come risultato. Questo è diverso dal risultato di magnitudo dei segni sopra. Ancora una volta, ci sono due codifica per 0 usando questo metodo.

Completamento a due: il valore negativo è l'inverso bitwise del valore positivo, più 1. Nel sistema a tre bit:

000  =  0
001  =  1
010  =  2
011  =  3
100  = -4
101  = -3
110  = -2
111  = -1

Se aggiungo da 1 a 3, traboccerò di -4 di conseguenza, che è diverso dai due metodi precedenti. Si noti che abbiamo una gamma leggermente più ampia di valori [-4, 3] e una sola rappresentazione per 0.

Il complemento di due è probabilmente il metodo più comune per rappresentare i valori firmati, ma non è l'unico, quindi lo standard C non può fare alcuna garanzia di ciò che accadrà quando trabocchi un tipo intero firmato. Quindi lascia il comportamento non definito Quindi il compilatore non deve affrontare l'interpretazione di più rappresentazioni.

Il comportamento indefinito Viene da problemi di portabilità precoce quando i tipi interi firmati potrebbero essere rappresentati come segno e grandezza, il complemento o il complemento di due.

Al giorno d'oggi, tutte le architetture rappresentano i numeri interi come complementi di due che si avvolgono. Ma fai attenzione: poiché il tuo compilatore ha ragione a supporre che non eseguirai un comportamento indefinito, potresti incontrare strani bug quando l'ottimizzazione è attiva.

In un numero intero firmato a 8 bit, la definizione intuitiva di avvolgimento potrebbe sembrare come passare da +127 a -128-nel binario del complemento di due: 0111111 (127) e 1000000 (-128). Come puoi vedere, questo è il naturale progresso dell'incremento dei dati binari, senza considerarlo rappresentare un numero intero, firmato o non firmato. Contra conti intuitivamente, il trabocco effettivo avviene quando si sposta da -1 (11111111) a 0 (00000000) nel senso di avvolgimento del numero intero non firmato.

Questo non risponde alla domanda più profonda di quale sia il comportamento corretto quando un numero intero firmato trabocca perché non esiste un comportamento "corretto" in base allo standard.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top