C ++ en a confronto int senza segno
-
08-07-2019 - |
Domanda
Ho trovato questo nel codice su cui sto lavorando al momento e ho pensato che fosse la causa di alcuni problemi che sto riscontrando.
In un'intestazione da qualche parte:
enum SpecificIndexes{
//snip
INVALID_INDEX = -1
};
Successivamente, inizializzazione:
nextIndex = INVALID_INDEX;
e usa
if(nextIndex != INVALID_INDEX)
{
//do stuff
}
Debug del codice, i valori in nextIndex non hanno abbastanza senso (erano molto grandi) e ho scoperto che era stato dichiarato:
unsigned int nextIndex;
Quindi, l'impostazione iniziale su INVALID_INDEX stava sottovalutando int senza segno e impostandolo su un numero enorme. Ho pensato che fosse ciò che stava causando il problema, ma guardando più da vicino, il test
if(nextIndex != INVALID_INDEX)
Si stava comportando correttamente, cioè non ha mai eseguito il corpo dell'if se nextIndex era il "grande + più valore".
È corretto? Come sta succedendo questo? Il valore enum viene castato implicitamente in un int senza segno dello stesso tipo della variabile e quindi viene racchiuso nello stesso modo?
Soluzione
Sì a tutto. È un codice valido, è anche comunemente usato codice C ++ lato libreria, più nel moderno C ++ (è strano quando lo vedi per la prima volta ma è un modello molto comune nella realtà).
Quindi gli enum sono ints firmati, ma vengono implicitamente lanciati in ints non firmati, ora questo a seconda del compilatore potrebbe dare un avvertimento, ma è ancora molto comunemente usato, tuttavia è necessario eseguire il cast esplicito per renderlo chiaro ai manutentori.
Altri suggerimenti
gli enum possono essere rappresentati da tipi integrali con o senza segno a seconda che contengano valori negativi e come si sente il compilatore. L'esempio qui contiene un valore negativo e quindi deve essere rappresentato da un tipo integrale con segno.
Il confronto di uguaglianza tra tipi firmati e non firmati è sicuro e di solito fa ciò che l'autore intendeva: il valore firmato verrà prima convertito in non firmato e il risultato di ciò è definito dallo standard C ++ ed è intuitivo (almeno è una volta che conosci il tipo di destinazione. Tranne forse se i numeri interi non sono un complemento a due. Quindi forse non è così intuitivo, ma normalmente non causa problemi.
È più probabile che il confronto degli ordini provochi errori. Ad esempio:
SpecificIndexes value = INVALID_VALUE;
return (value >= 0);
restituisce false, ma:
unsigned int value = INVALID_VALUE;
return (value >= 0);
restituisce vero. A volte l'autore non apprezzerà la differenza, soprattutto se il tipo di "valore" non è così evidente nel punto di utilizzo. Il compilatore potrebbe anche avvertire del secondo esempio, perché (value > = 0) è una tautologia.
In effetti, -1 viene implicitamente proiettato al suo valore non firmato equivalente quando viene assegnato a nextValue. L'equivalente unsigned è il valore con la stessa rappresentazione bit per bit (che è 111111111111 ..., questo è il valore massimo senza segno).
In seguito, nella dichiarazione di confronto, accade un altro cast implicito.
Quindi funziona ora, ma potrebbe causare problemi in futuro. Non è mai una buona idea mescolare valori firmati e non firmati.
Sì, credo che gli enumerati siano firmati. Cambia
unsigned int nextIndex;
a
int nextIndex;
e il tuo programma dovrebbe funzionare.
Lo standard C ++ consente a un'implementazione di usare un tipo firmato per gli enum ma non lo richiede. Pertanto, in generale non si può presumere che sia sicuro inserire numeri negativi in ??un enum.