2014-09-01 24 views
8

Sto studiando il linguaggio C++ e ho qualche dubbio sulla conversione del tipo, mi può spiegare che cosa accade in un'espressione come questa:cosa succede quando mischio tipi firmati e non firmati?

unsigned int u = 10; 
int a = -42; 
std::cout << u - a << std::endl; 

Qui so che il risultato sarà 52 Se si applica la regole quando abbiamo due operatori matematici. Ma mi chiedo che cosa succede quando il compilatore per convertire un valore in un non firmato crea un temporaneo di tipo senza segno, cosa succede dopo? L'espressione ora dovrebbe essere 10 -4294967254.

+0

Perché non provi a vedere? – dandan78

+0

@ dandan78 Voglio capire come funziona il compilatore sul sottostante –

+2

@ dandan78: a volte può essere ingenuo; soprattutto se qualsiasi aspetto del calcolo non è definito. – Bathsheba

risposta

9

In termini semplici, se si mescolano i tipi dello stesso valore (nella sequenza di int, long int, long long int), il tipo unsigned "vince" ed i calcoli vengono eseguiti all'interno di quel tipo unsigned . Il risultato è dello stesso tipo senza segno.

Se si mescolano tipi di rango diverso, il tipo più elevato "vince", se può rappresentare tutti i valori del tipo con classificazione inferiore. I calcoli vengono eseguiti all'interno di quel tipo. Il risultato è di quel tipo.

Infine, se il tipo con classificazione più alta non può rappresentare tutti i valori di tipo con classificazione inferiore, viene utilizzata la versione senza segno del tipo con classificazione più alta. Il risultato è di quel tipo.

Nel tuo caso si tipi misti dello stesso valore (int e unsigned int), il che significa che l'intera espressione viene valutata all'interno unsigned int tipo. L'espressione, come hai affermato correttamente, è ora 10 - 4294967254 (per 32 bit int). I tipi non firmati rispettano le regole dell'aritmetica modulo con 2^32 (4294967296) come modulo. Se si calcola attentamente il risultato (che può essere espresso aritmeticamente come 10 - 4294967254 + 4294967296), risulterà come previsto 52.

+0

scusa mi sono perso, quando expressio diventa: unsigned int temporary = 10 - 4294967254 (ok ho capito questo) ma non riesco a capire perché l'espressione diventa 10 - 4294967254 + 4294967296 (perché aggiungi all'espressione il modulo aritmetica?). –

+0

@Piero Borrelli: un modo per calcolare l'equivalente 'modulo N' di un valore negativo' V' è di aggiungere 'N' ad esso tutte le volte necessarie (' V + N', 'V + 2N',' V + 3N' e così via) fino a quando non si preme il primo valore non negativo. In caso di operazioni additive in C++, un risultato matematicamente negativo richiede che il valore modulo venga aggiunto una sola volta per ottenere il risultato non firmato corretto. – AnT

+0

@Piero Borrelli: Certo, questa è una regola puramente aritmetica. Il compilatore non deve fare nulla del genere. Non deve preoccuparsi affatto. Se i valori negativi sono rappresentati attraverso il complemento a 2, una semplice reinterpretazione di quella rappresentazione come non firmata fornisce immediatamente il risultato corretto. – AnT

1

1) A causa di regole di promozione standard, il signed tipo a viene promosso a un unsigned tipo prima di sottrazione. Che la promozione avviene secondo questa regola (C++ standard da 4,7/2):

Se il tipo di destinazione è senza segno, il valore risultante è il meno intero senza segno congruente al numero intero sorgente (modulo 2n dove n è la numero di bit utilizzati per rappresentare il tipo senza segno).

Algebricamente a diventa un numero positivo molto ampio e sicuramente maggiore di u.

2) u - a è un anonimo temporanea e sarà un unsigned tipo . (È possibile verificare ciò scrivendo auto t = u - a e ispezionando il tipo di t nel debugger.) Matematicamente questo sarà un numero negativo ma sulla conversione implicita al tipo unsigned, viene invocata una regola wraparound simile a quella precedente.

In breve, le due operazioni di conversione hanno effetti uguali e opposti e il risultato sarà 52. In pratica, il compilatore potrebbe ottimizzare tutte queste conversioni.

-1

ecco il codice smontare dice:

esso primi set -42 al suo complemento e fanno l'operazione sub. in modo che il risultato è 10 + 42 0x0000000000400835 <+8>: movl $0xa,-0xc(%rbp) 0x000000000040083c <+15>: movl $0xffffffd6,-0x8(%rbp) 0x0000000000400843 <+22>: mov -0x8(%rbp),%eax 0x0000000000400846 <+25>: mov -0xc(%rbp),%edx 0x0000000000400849 <+28>: sub %eax,%edx 0x000000000040084b <+30>: mov %edx,%eax

+1

In generale, il codice smontato non può servire come fonte significativa per la comprensione della semantica a livello di linguaggio. La generazione del codice è una funzione a senso unico. Non è possibile "rintracciarlo". cioè per capire cosa stava effettivamente cercando di fare il compilatore guardando il codice generato. – AnT

+0

Grazie per il tuo commento. –