In C/C++, a cosa serve unsigned char
? In che modo è diverso da un char
regolare?
In C++, ci sono tre distinti tipi di caratteri:
char
signed char
unsigned char
Se stai usando i tipi di caratteri per text , usa il char
non qualificato:
'a'
o '0'
."abcde"
Funziona anche come valore numerico, ma non è specificato se quel valore è considerato come firmato o non firmato. Fai attenzione ai confronti tra i personaggi attraverso le disuguaglianze, anche se ti limiti a ASCII (0-127) sei quasi sicuro.
Se stai usando tipi di caratteri come numbers , usa:
signed char
, che fornisce almeno l'intervallo da -127 a 127. (Da -128 a 127 è comune)unsigned char
, che fornisce almeno l'intervallo da 0 a 255."Almeno", perché lo standard C++ fornisce solo l'intervallo minimo di valori che ciascun tipo numerico deve coprire. sizeof (char)
è richiesto per essere 1 (cioè un byte), ma un byte potrebbe in teoria essere per esempio 32 bit.sizeof
DOVREBBE COMUNQUE RIPORTARE LE SUE DIMENSIONI COME 1
- che significa che potrebbe avere sizeof (char) == sizeof (long) == 1
.
Questo dipende dall'implementazione, poiché lo standard C NON definisce la firma di char
. A seconda della piattaforma, char può essere signed
o unsigned
, quindi è necessario chiedere esplicitamente signed char
o unsigned char
se l'implementazione dipende da esso. Usa solo char
se intendi rappresentare caratteri da stringhe, poiché ciò corrisponderà a ciò che la tua piattaforma inserisce nella stringa.
La differenza tra signed char
e unsigned char
è come ci si aspetterebbe. Sulla maggior parte delle piattaforme, signed char
sarà un numero di complemento a due bit di 8 bit che va da -128
a 127
, e unsigned char
sarà un numero intero senza segno a 8 bit (0
to 255
). Nota che lo standard NON richiede che i tipi char
abbiano 8 bit, solo che sizeof(char)
restituisce 1
. È possibile ottenere il numero di bit in un carattere con CHAR_BIT
in limits.h
. Oggi ci sono poche piattaforme se questa sarà diversa da 8
.
C'è un bel riassunto di questo numero qui .
Come altri hanno menzionato da quando ho postato questo, è meglio usare int8_t
e uint8_t
se si vogliono rappresentare interi piccoli.
Perché sento che è davvero richiesto, voglio solo enunciare alcune regole di C e C++ (sono le stesse in questo senso). Innanzitutto, tutti i bit di unsigned char
partecipano alla determinazione del valore se qualsiasi oggetto char non firmato. In secondo luogo, unsigned char
è esplicitamente dichiarato non firmato.
Ora, ho avuto una discussione con qualcuno su cosa succede quando converti il valore -1
di tipo int in unsigned char
. Ha rifiutato l'idea che il unsigned char
risultante abbia tutti i suoi bit impostati su 1, perché era preoccupato per la rappresentazione del segno. Ma lui non deve. Sta immediatamente seguendo questa regola che la conversione fa ciò che è inteso:
Se il nuovo tipo non è firmato, il valore viene convertito aggiungendo o sottraendo ripetutamente un valore superiore al valore massimo che può essere rappresentato nel nuovo tipo finché il valore non si trova nell'intervallo del nuovo tipo. (
6.3.1.3p2
in una bozza C99)
Questa è una descrizione matematica. C++ lo descrive in termini di modulo di calcolo, che produce la stessa regola. Ad ogni modo, ciò che è non garantito è che tutti i bit nell'intero -1
sono uno prima della conversione. Quindi, che cosa abbiamo in modo che possiamo affermare che il unsigned char
risultante ha tutti i suoi bit CHAR_BIT
convertiti in 1?
UCHAR_MAX+1
a -1
produrrà un valore nell'intervallo, ovvero UCHAR_MAX
Questo è abbastanza, in realtà! Quindi ogni volta che vuoi avere un unsigned char
che abbia tutti i suoi bit uno, lo fai
unsigned char c = (unsigned char)-1;
Ne consegue anche che una conversione è non solo troncando i bit di ordine superiore. L'evento fortunato per il complemento a due è che è solo un troncamento lì, ma lo stesso non è necessariamente vero per altre rappresentazioni di segni.
Come ad esempio gli usi di unsigned char :
unsigned char è spesso usato in computer graphics, che molto spesso (anche se non sempre) assegna un singolo byte a ciascun componente di colore. È comune vedere un colore RGB (o RGBA) rappresentato come 24 (o 32) bit, ciascuno un unsigned char . Dato che unsigned char values rientrano nell'intervallo [0,255], i valori sono tipicamente interpretati come:
Così si finirebbe con RGB rosso come (255,0,0) -> (100% rosso, 0% verde, 0% blu).
Perché non usare un signed char ? L'aritmetica e il cambio di bit diventano problematici. Come già spiegato, un intervallo di signed char è sostanzialmente spostato di -128. Un metodo molto semplice e ingenuo (per lo più inutilizzato) per convertire da RGB a scala di grigi è la media di tutti e tre i componenti del colore, ma questo si verifica quando i valori dei componenti del colore sono negativi. Red (255, 0, 0) medie a (85, 85, 85) quando si utilizza unsigned char arithmetic. Tuttavia, se i valori fossero signed char s (127, -128, -128), avremmo finito con (-99, -99, -99), che sarebbe (29, 29, 29 ) nel nostro unsigned char space, che non è corretto.
Se si desidera utilizzare un carattere come un numero intero piccolo, il modo più sicuro per farlo è con i tipi int8_t
and uint8_t
.
signed char
ha intervallo da -128 a 127; unsigned char
ha intervallo da 0 a 255.
char
sarà equivalente al char firmato o al char unsigned, a seconda del compilatore, ma è un tipo distinto.
Se stai usando le stringhe in stile C, usa char
. Se è necessario utilizzare i caratteri per l'aritmetica (piuttosto raro), specificare esplicitamente la firma o la firma per la portabilità.
char
e unsigned char
non sono garantiti come tipi a 8 bit su tutte le piattaforme, sono garantiti per essere 8-bit o più grandi. Alcune piattaforme hanno 9 bit, 32 bit o 64 bit byte . Tuttavia, le piattaforme più comuni oggi (Windows, Mac, Linux x86, ecc.) Hanno byte da 8 bit.
In termini di valori diretti viene utilizzato un carattere normale quando i valori sono noti tra CHAR_MIN
e CHAR_MAX
mentre un char senza segno fornisce il doppio dell'intervallo sul lato positivo. Ad esempio, se CHAR_BIT
è 8, l'intervallo di char
regolare è garantito solo per [0, 127] (perché può essere firmato o non firmato) mentre unsigned char
sarà [0, 255] e signed char
sarà [-127, 127 ].
In termini di ciò per cui è utilizzato, gli standard consentono agli oggetti del POD (semplici vecchi dati) di essere convertiti direttamente in una matrice di caratteri non firmati. Ciò consente di esaminare la rappresentazione e i pattern di bit dell'oggetto. La stessa garanzia di punizioni di tipo sicuro non esiste per char o char firmato.
unsigned char
accetta solo valori positivi .... come 0 a 255
mentre
signed char
accetta valori sia positivi che negativi .... come -128 a +127
Un char senza segno è un valore di byte (senza segno) (da 0 a 255). Potresti pensare a "char" in termini di "personaggio", ma in realtà è un valore numerico. Il "char" normale è firmato, quindi hai 128 valori, e questi valori si associano ai caratteri usando la codifica ASCII. Ma in entrambi i casi, ciò che stai memorizzando è un valore in byte.
Se ti piace usare vari tipi di lunghezza e firma specifici, probabilmente stai meglio con uint8_t, int8_t, uint16_t, ecc semplicemente perché fanno esattamente quello che dicono.
Un char senza segno utilizza il bit che è riservato per il segno di un carattere normale come un altro numero. Ciò cambia l'intervallo su [0 - 255] rispetto a [-128 - 127].
I caratteri generalmente non firmati vengono utilizzati quando non si desidera un segno. Questo farà la differenza quando si fanno cose come spostare i bit (shift estende il segno) e altre cose quando si ha a che fare con un char come byte piuttosto che usarlo come un numero.
il char non firmato è il cuore di tutti i trucchetti. In quasi tutti i compilatori per tutte le piattaforme, un char senza segno è semplicemente un BYTE. Un numero intero senza segno di (solitamente) 8 bit. che può essere trattato come un piccolo numero intero o un pacchetto di bit.
In aggiunta, come ha detto qualcun altro, lo standard non definisce il segno di un carattere. quindi hai 3 diversi tipi "char": char, signed char, unsigned char.
Alcuni googling trovato questo , dove le persone hanno avuto una discussione su questo.
Un char senza segno è fondamentalmente un singolo byte. Quindi, dovresti usarlo se hai bisogno di un byte di dati (ad esempio, forse vuoi usarlo per impostare i flag on e off per essere passati a una funzione, come spesso accade nell'API di Windows).
il carattere non firmato prende solo valori positivi: da 0 a 255 caratteri scritti prende valori positivi e negativi: da -128 a +127
citato dal libro "the c programming laugage":
Il qualificatore signed
o unsigned
può essere applicato a char o qualsiasi intero. i numeri senza segno sono sempre positivi o pari a zero e rispettano le leggi dell'aritmetico modulo 2 ^ n, dove n è il numero di bit nel tipo. Quindi, ad esempio, se i caratteri sono 8 bit, le variabili char non firmate hanno valori compresi tra 0 e 255, mentre i caratteri firmati hanno valori compresi tra -128 e 127 (in una macchina a complemento di due). Se i caratteri semplici sono firmati o non firmati è macchina -dipendenti, ma i caratteri stampabili sono sempre positivi.