2010-08-02 12 views
5

Ecco il codice molto semplice,Unsigned e firmato confronto

#include <iostream> 
using namespace std; 
int main() { 
    unsigned int u=10; 
    int i; 
    int count=0; 
    for (i=-1;i<=u;i++){ 
     count++; 
    } 
    cout<<count<<"\n"; 
    return 0; 
} 

Il valore di conteggio è 0. Perché?

+1

Per inciso, si dovrebbe usare 'std :: endl' invece di inserire' \ n' in un flusso, perché 'std :: endl' sia è portatile e assicura che l'output sia visualizzato immediatamente. –

+1

@ Ben: '\ n' è altrettanto portatile; dovresti usare solo "endl" se vuoi che il flusso venga scaricato in questo momento. –

+0

'\ n' è portatile (viene convertito alla sequenza di interruzione di riga della piattaforma) e non comporta il sovraccarico di scarico immediato del flusso. Dovresti usare quello che ha la semantica che vuoi: se vuoi che il flusso venga svuotato, usa 'endl', se vuoi solo un'interruzione di riga, usa' \ n'. – jalf

risposta

8

Entrambi gli operandi di <= devono essere promosso al stesso tipo.

Evidentemente sono promossi a unsigned int (non ho la regola dello standard di fronte a me, lo cercherò in un secondo). Poiché (unsigned int)(-1) <= u è falso, il ciclo non viene mai eseguito.

La regola si trova nella sezione 5 (espressione) della norma, comma 10, che recita (ho evidenziato la regola che si applica qui):

Molti operatori binari che si aspettano operandi di aritmetica o il tipo di enumerazione causa le conversioni e restituisce i tipi di risultato in modo simile. Lo scopo è quello di produrre un tipo comune, che è anche il tipo del risultato. Questo modello è chiamato usuali conversioni aritmetiche, che sono definite come segue:

  • Se uno degli operandi è di tipo censimento ambito (7.2), non vengono eseguite conversioni; se l'altro operando non ha lo stesso tipo, l'espressione è mal formata.
  • Se uno degli operandi è di tipo long double, l'altro deve essere convertito in long double.
  • Altrimenti, se uno degli operandi è doppio, l'altro deve essere convertito in doppio.
  • Altrimenti, se uno degli operandi è mobile, l'altro deve essere convertito in float.
  • In caso contrario, le promozioni integrali (4.5) devono essere eseguite su entrambi gli operandi. 60 Quindi le seguenti regole devono essere applicate agli operandi promossi:
  • Se entrambi gli operandi hanno lo stesso tipo, non è necessaria alcuna ulteriore conversione.
  • Altrimenti, se entrambi gli operandi hanno tipi interi con segno o entrambi hanno tipi interi senza segno, l'operando con il tipo di rango di conversione intero minore deve essere convertito nel tipo dell'operando con grado maggiore.
  • Altrimenti, se l'operando che ha un numero intero senza segno ha una posizione superiore o uguale al grado del tipo di altro operando, l'operando con tipo intero con segno deve essere convertito nel tipo di operando con tipo intero senza segno .
  • Altrimenti, se il tipo di operando con tipo intero con segno può rappresentare tutti i valori del tipo di operando con tipo intero senza segno, l'operando con tipo intero senza segno deve essere convertito nel tipo di operando con segno tipo intero.
  • In caso contrario, entrambi gli operandi devono essere convertiti nel tipo intero senza segno corrispondente al tipo di operando con tipo intero con segno.
1

Its perché -1 è castato come int unsigned, quindi il codice ciclo for non viene mai eseguito.

Provare a compilare con -Wall -Wextra modo da poter ottenere le relative avvertenze (se non far loro finora, e la compilazione con g ++)

http://en.wikipedia.org/wiki/Two's_complement

+0

grazie solo vorrei chiederti una cosa che ti darò il link alla mia domanda e, per favore, dimmi il motivo per cui diminuiscono il mio voto o fanno un downvote ok? voglio avere una buona reputazione e provare a postare buone domande ma la diminuiscono –

+1

@davit: l'altra tua domanda è stata downvoted perché il compilatore ti ha detto esattamente cosa c'era (mancava un punto e virgola) ma hai postato la tua domanda qui cercando di risolvere il problema da soli. –

4

Durante il confronto (i <= u), i viene aggiornato a un intero senza segno, e nel processo -1 viene convertito UINT_MAX.

Una conversione di un numero negativo a un unsigned int aggiungerà (UINT_MAX + 1) a quel numero, in modo da -1 diventa UINT_MAX, -2 diventa UINT_MAX - 1, ecc

Se ci pensate, uno doveva essere convertito all'altro affinché il confronto potesse funzionare, e di norma il compilatore converte il valore firmato in non firmato. In questo caso, ovviamente, avrebbe più senso convertire il valore unsigned in signed, ma il compilatore non può semplicemente decidere di seguire una specifica diversa in base a ciò che si intende. È necessario eseguire il cast esplicito dell'int unsigned per firmarlo (o semplicemente averlo come firmato per intero) qui.

+0

La tua regola non funziona. In realtà viene aggiunto 2 ** 32, che è 'UINT_MAX + 1', non' UINT_MAX - 1'. –

+0

Grazie Ben, l'ho corretto - a + ora. – thomasrutter

+1

WRT i tuoi nuovi commenti, la conversione da firmata a unsigned è ben definita per tutti gli input, ma la conversione da unsigned a signed può richiamare un comportamento definito dall'implementazione (qui non lo sarebbe, poiché il valore di 'u' è 10 che si adatta a 'int'). –

0

Su un sistema in cui un intero è memorizzato in 4 byte, credo che il valore di -1 sia uguale al valore di 2147483649 (1000 0000 0000 0000 0000 0000 0000 0001) - È 1 con l'MSB impostato su 1 per indicare è negativo

+1

No, nella rappresentazione a complemento a due '-1' è memorizzata come tutti. Ma la rappresentazione effettiva non ha importanza, perché lo standard C++ definisce la conversione da un tipo integrale firmato a un non firmato come congruente nell'aritmetica base-N del modulo. –

+1

Anche se questo sarebbe vero su un sistema di grandezza del segnale, quelli sono ora estremamente rari. I sistemi più ragionevolmente attuali usano il complemento a 2 per i numeri interi, e in questo caso -1 sarà rappresentato da tutti i bit impostati a 1 (nel qual caso la conversione da firmata a non firmata non richiede alcuna modifica nei dati, solo un cambiamento nel modo in cui è interpretato). –

+1

@Jerry: la grandezza del segnale non è affatto rara. Lo richiede IEEE 754.Praticamente ogni computer utilizza interi a due complementi e rappresentazioni a virgola mobile di magnitudo di segno. –

1

Questo perché i viene promosso a un valore senza segno prima del confronto. Questo lo imposterà sul valore di UINT_MAX, che su una macchina a 32 bit equivale a 4294967295. Così il vostro ciclo è essenzialmente la stessa:

// will never run 
for (i = 4294967295; i <= u; i++) { 
    count++; 
} 
Problemi correlati