Uso gli input non firmati per rendere più chiaro il mio codice e le sue intenzioni. Una cosa che faccio per evitare conversioni implicite impreviste quando si esegue l'aritmetica con entrambi i tipi con segno e senza segno è di usare un corto senza segno (di solito 2 byte) per le variabili non firmate. Questo è efficace per un paio di motivi:
- Quando esegui operazioni aritmetiche con le tue brevi variabili e letterali senza segno (che sono di tipo int) o variabili di tipo int, questo assicura che la variabile unsigned sarà sempre promossa a un int prima di valutare l'espressione, poiché int ha sempre un valore più alto rango che corto. Ciò evita qualsiasi comportamento imprevisto eseguendo operazioni aritmetiche con tipi firmati e non firmati, presupponendo che il risultato dell'espressione si inserisca in un int firmato ovviamente.
- La maggior parte delle volte, le variabili non firmate che stai utilizzando non superano il valore massimo di un corto a 2 byte senza segno (65.535)
Il principio generale è che il tipo delle variabili non firmate deve avere un grado inferiore rispetto al tipo delle variabili firmate per assicurare la promozione al tipo firmato. Quindi non avrai alcun comportamento di overflow imprevisto. Ovviamente non è possibile garantire questo tutto il tempo, ma (la maggior parte) spesso è possibile garantirlo.
Ad esempio, recentemente ho avuto qualche ciclo per qualcosa del genere:
const unsigned short cuint = 5;
for(unsigned short i=0; i<10; ++i)
{
if((i-2)%cuint == 0)
{
//Do something
}
}
Il letterale '2' è di tipo int. Se ero un int unsigned invece di un unsigned short, quindi nella sottoespressione (i-2), 2 sarebbe promosso a un int unsigned (poiché int unsigned ha una priorità più alta di signed int). Se i = 0, allora la sottoespressione è uguale a (0u-2u) = un valore enorme a causa di un overflow. Stessa idea con i = 1. Tuttavia, dato che i è un corto senza segno, viene promosso allo stesso tipo di letterale '2', che è firmato int, e tutto funziona bene.
Per una maggiore sicurezza: nel raro caso in cui l'architettura che stai implementando fa sì che int sia 2 byte, questo potrebbe far sì che entrambi gli operandi nell'espressione aritmetica siano promossi a int unsigned nel caso in cui la variabile breve unsigned non si inseriscono nell'int intatto da 2 byte, l'ultimo dei quali ha un valore massimo di 32.767 < 65.535. (Vedi link per maggiori dettagli). Per evitare questo, puoi semplicemente aggiungere una static_assert al tuo programma come segue:
static_assert(sizeof(int) == 4, "int must be 4 bytes");
e non verrà compilato su architetture dove int è 2 byte.