In C / C ++, a cosa unsigned char
serve un? In che cosa differisce da un normale char
?
In C / C ++, a cosa unsigned char
serve un? In che cosa differisce da un normale char
?
Risposte:
In C ++, ci sono tre tipi di caratteri distinti :
char
signed char
unsigned char
Se si utilizzano tipi di caratteri per il testo , utilizzare la non qualificata char
:
'a'
o '0'
."abcde"
Funziona anche come valore numerico, ma non è specificato se quel valore sia trattato come firmato o non firmato. Fai attenzione ai confronti dei personaggi attraverso le disuguaglianze, anche se se ti limiti ad ASCII (0-127) sei quasi al sicuro.
Se si utilizzano tipi di carattere come numeri , utilizzare:
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 ogni tipo numerico deve coprire. sizeof (char)
è necessario che sia 1 (ovvero un byte), ma in teoria un byte potrebbe essere ad esempio 32 bit. sizeof
sarebbe ancora segnalare la sua dimensione come1
- il che significa che si potrebbe avere sizeof (char) == sizeof (long) == 1
.
sizeof
perché non è una funzione ma un operatore. È uno stile ancora migliore omettere la parentesi quando si prende la dimensione di una variabile. sizeof *p
o sizeof (int)
. Questo chiarisce rapidamente se si applica a un tipo o una variabile. Allo stesso modo, è anche ridondante mettere la parentesi dopo return
. Non è una funzione.
char
: è il tipo di caratteri letterali come 'a'
o '0'
." è vero in C ++ ma non in C. In C, 'a'
è un int
.
Ciò 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 richiedere esplicitamente signed char
o unsigned char
se l'implementazione dipende da esso. Utilizzalo solo char
se intendi rappresentare i caratteri delle stringhe, poiché corrisponderanno a ciò che la tua piattaforma inserisce nella stringa.
La differenza tra signed char
e unsigned char
è come ti aspetteresti. Sulla maggior parte delle piattaforme, signed char
sarà un numero di complemento di due bit a 8 bit che va da -128
a 127
e unsigned char
sarà un numero intero senza segno a 8 bit ( 0
a 255
). Si noti che lo standard NON richiede che i char
tipi abbiano 8 bit, solo quello sizeof(char)
restituito 1
. È possibile ottenere il numero di bit in un carattere con CHAR_BIT
in limits.h
. Ci sono poche o nessuna piattaforma oggi dove questo sarà qualcosa di diverso 8
, però.
C'è un bel riassunto di questo problema qui .
Come altri hanno già detto da quando l'ho pubblicato, stai meglio usando int8_t
e uint8_t
se vuoi davvero rappresentare piccoli numeri interi.
CHAR_BIT
lo standard deve contenere almeno 8 bit.
Perché penso che sia davvero richiesto, voglio solo dichiarare alcune regole di C e C ++ (sono le stesse in questo senso). In primo luogo, tutti i bit di unsigned char
partecipare nella determinazione del valore se qualsiasi oggetto char senza segno. In secondo luogo, unsigned char
viene esplicitamente dichiarato non firmato.
Ora, ho avuto una discussione con qualcuno su cosa succede quando converti il valore -1
di type int in unsigned char
. Ha rifiutato l'idea che il risultato unsigned char
abbia tutti i suoi bit impostati su 1, perché era preoccupato per la rappresentazione dei segni. Ma non deve. È immediatamente seguito a questa regola che la conversione fa ciò che si intende:
Se il nuovo tipo non è firmato, il valore viene convertito aggiungendo o sottraendo ripetutamente uno in più rispetto al valore massimo che può essere rappresentato nel nuovo tipo fino a quando il valore non rientra nell'intervallo del nuovo tipo. (
6.3.1.3p2
in una bozza C99)
Questa è una descrizione matematica. C ++ lo descrive in termini di modulo modulo, che cede alla stessa regola. Comunque, ciò che non è garantito è che tutti i bit nell'intero -1
sono uno prima della conversione. Quindi, cosa abbiamo in modo da poter affermare che il risultato unsigned char
ha tutti i suoi CHAR_BIT
bit trasformati in 1?
UCHAR_MAX+1
a si -1
otterrà un valore nell'intervallo, vale a direUCHAR_MAX
Questo è abbastanza, in realtà! Quindi ogni volta che vuoi avere uno unsigned char
con tutti i suoi bit, lo fai
unsigned char c = (unsigned char)-1;
Ne consegue anche che una conversione non sta semplicemente troncando bit di ordine superiore. Il fortunato evento per il complemento a due è che lì è solo un troncamento, ma lo stesso non è necessariamente vero per altre rappresentazioni di segni.
UCHAR_MAX
?
(unsigned type)-1
è una specie di linguaggio. ~0
non lo è.
int x = 1234
e char *y = &x
. Rappresentazione binaria di 1234
is 00000000 00000000 00000100 11010010
. La mia macchina è un po 'endian, quindi la inverte e la memoria 11010010 00000100 00000000 00000000
LSB viene prima di tutto. Ora parte principale. se io uso printf("%d" , *p)
. printf
leggerà il primo byte 11010010
solo l'output è -46
ma 11010010
è 210
per questo che stampa -46
. Sono davvero confuso, immagino che un po 'di promozione alla promozione dei numeri interi stia facendo qualcosa, ma non lo so.
Come ad esempio gli usi di caratteri non firmati :
unsigned char
viene spesso utilizzato nella computer grafica, 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
. Poiché i unsigned char
valori rientrano nell'intervallo [0,255], i valori vengono generalmente interpretati come:
Quindi potresti finire con RGB rosso come (255,0,0) -> (100% rosso, 0% verde, 0% blu).
Perché non usare un signed char
? L'aritmetica e lo spostamento dei bit diventano problematici. Come già spiegato, signed char
l'intervallo di a è sostanzialmente spostato di -128. Un metodo molto semplice e ingenuo (per lo più inutilizzato) per convertire RGB in scala di grigi è la media di tutti e tre i componenti di colore, ma ciò si traduce in problemi quando i valori dei componenti di colore sono negativi. Il rosso (255, 0, 0) ha una media di (85, 85, 85) quando si usa l' unsigned char
aritmetica. Tuttavia, se i valori fossero signed char
s (127, -128, -128), finiremmo con (-99, -99, -99), che sarebbe (29, 29, 29) nel nostro unsigned char
spazio, il che non è corretto .
Se si desidera utilizzare un carattere come un intero piccolo, il modo più sicuro per farlo è con i tipi int8_t
e uint8_t
.
int8_t
e uint8_t
sono opzionali e non definiti su architetture in cui la dimensione dei byte non è esattamente di 8 bit. Viceversa, signed char
e unsigned char
sono sempre disponibili e in grado di conservare almeno 8 bit. Potrebbe essere un modo comune ma non il più sicuro .
signed char
e unsigned char
? O consiglieresti una migliore alternativa "più sicura" in quel caso particolare? Ad esempio, attenersi ai tipi interi "reali" signed int
e unsigned int
invece per qualche motivo?
signed char
e unsigned char
è portatile per tutte le implementazioni conformi e consente di risparmiare spazio di archiviazione ma può causare un aumento delle dimensioni del codice. In alcuni casi, si risparmierebbe più spazio di archiviazione memorizzando piccoli valori in bitfield o singoli bit di tipi interi regolari. Non esiste una risposta assoluta a questa domanda, la pertinenza di questo approccio dipende dal caso specifico a portata di mano. E questa risposta non affronta comunque la domanda.
char
e unsigned char
non è garantito che siano tipi a 8 bit su tutte le piattaforme: sono garantiti a 8 bit o più. Alcune piattaforme hanno byte a 9, 32 o 64 bit . Tuttavia, le piattaforme più comuni oggi (Windows, Mac, Linux x86, ecc.) Hanno byte a 8 bit.
signed char
ha un intervallo da -128 a 127; unsigned char
ha un intervallo da 0 a 255.
char
sarà equivalente al carattere con segno o al carattere senza segno, a seconda del compilatore, ma è un tipo distinto.
Se stai usando stringhe in stile C, usa semplicemente char
. Se è necessario utilizzare i caratteri per l'aritmetica (piuttosto raro), specificare esplicitamente firmato o non firmato per la portabilità.
An unsigned char
è un valore di byte senza segno (da 0 a 255). Potresti pensare char
in termini di essere un "personaggio" ma è davvero un valore numerico. Il normale char
è firmato, quindi hai 128 valori e questi valori sono associati a caratteri usando la codifica ASCII. Ma in entrambi i casi, ciò che stai memorizzando è un valore in byte.
In termini di valori diretti viene utilizzato un carattere normale quando si sa che i valori sono compresi tra CHAR_MIN
e CHAR_MAX
mentre un carattere senza segno fornisce il doppio dell'intervallo sull'estremità positiva. Ad esempio, se CHAR_BIT
è 8, l'intervallo del regolare char
è garantito solo su [0, 127] (perché può essere firmato o non firmato) mentre unsigned char
sarà [0, 255] esigned char
sarà [-127, 127].
In termini di utilizzo, gli standard consentono agli oggetti di POD (semplici vecchi dati) di essere convertiti direttamente in una matrice di caratteri non firmati. Ciò consente di esaminare la rappresentazione e gli schemi di bit dell'oggetto. La stessa garanzia di punzonatura di tipo sicuro non esiste per il carattere o il carattere firmato.
unsigned char
, non una matrice specificamente, e qualsiasi "conversione" è solo formalmente definito dal copiando dall'oggetto reale, dichiarata matrice di unsigned char
e quindi ispezionare quest'ultimo. Non è chiaro se l'OR possa essere reinterpretato direttamente come tale array, con le indennità per l'aritmetica del puntatore che ciò comporterebbe, ovvero se ==
"array" di "sequenza " in questo utilizzo. C'è un numero principale 1701 aperto nella speranza di ottenere questo chiarimento. Per fortuna, poiché questa ambiguità mi sta davvero infastidendo di recente.
unsigned char
dell'OR e quindi procedere utilizzando ++ptr
da lì per leggere ogni byte di esso ... ma AFAICT, non è specificamente definito come consentito, quindi siamo lasciato a dedurre che è "probabilmente OK" da molti altri passaggi (e in molti modi, la semplice esistenza di memcpy
) nello Standard, simile a un puzzle. Quale non è l'ideale. Bene, forse la formulazione migliorerà alla fine. Ecco il problema CWG che ho citato ma che mancava di spazio per il collegamento - open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1701
unsigned char
è il cuore di tutti i trucchi. In quasi TUTTI i compilatori per TUTTE le piattaforme un unsigned char
è semplicemente un byte e un numero intero senza segno di (solitamente) 8 bit che può essere trattato come un intero piccolo o un pacchetto di bit.
Inoltre, come ha detto qualcun altro, lo standard non definisce il segno di un carattere. in modo da avere 3 distinte char
tipologie: char
, signed char
, unsigned char
.
Se ti piace utilizzando vari tipi di specifica lunghezza e signedness, siete probabilmente meglio con uint8_t
, int8_t
, uint16_t
, ecc semplicemente perché fanno esattamente quello che dicono.
Alcuni googling hanno trovato questo , dove le persone hanno discusso di questo.
Un carattere senza segno è sostanzialmente un singolo byte. Quindi, lo useresti se hai bisogno di un byte di dati (ad esempio, forse vuoi usarlo per attivare e disattivare i flag da passare a una funzione, come spesso accade nell'API di Windows).
Un carattere senza segno utilizza il bit riservato per il segno di un carattere normale come un altro numero. Ciò modifica l'intervallo su [0 - 255] anziché [-128 - 127].
I caratteri generalmente non firmati vengono utilizzati quando non si desidera un segno. Ciò 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 carattere come byte anziché usarlo come numero.
citato dal libro "the laugage di programmazione c":
Il qualificatore signed
o unsigned
può essere applicato a char o a qualsiasi numero intero. i numeri senza segno sono sempre positivi o zero e obbediscono alle leggi dell'aritmetica modulo 2 ^ n, dove n è il numero di bit nel tipo. Quindi, ad esempio, se i caratteri sono 8 bit, le variabili dei caratteri senza segno hanno valori compresi tra 0 e 255, mentre i caratteri con segno hanno valori compresi tra -128 e 127 (in una macchina a complemento a due.) Se i caratteri semplici sono firmati o non firmati è macchina -dipendenti, ma i caratteri stampabili sono sempre positivi.
signed char
ed unsigned char
entrambi rappresentano 1 byte, ma hanno intervalli diversi.
Type | range
-------------------------------
signed char | -128 to +127
unsigned char | 0 to 255
In signed char
se consideriamo char letter = 'A'
, 'A' è rappresentare binaria di 65 ASCII/Unicode
, se 65 possono essere immagazzinate, -65 anche possono essere memorizzati. Non ci sono valori binari negativi inASCII/Unicode
lì per non preoccuparsi di valori negativi.
Esempio
#include <stdio.h>
int main()
{
signed char char1 = 255;
signed char char2 = -128;
unsigned char char3 = 255;
unsigned char char4 = -128;
printf("Signed char(255) : %d\n",char1);
printf("Unsigned char(255) : %d\n",char3);
printf("\nSigned char(-128) : %d\n",char2);
printf("Unsigned char(-128) : %d\n",char4);
return 0;
}
Produzione -:
Signed char(255) : -1
Unsigned char(255) : 255
Signed char(-128) : -128
Unsigned char(-128) : 128