In C / C ++, a cosa unsigned charserve un? In che cosa differisce da un normale char?
In C / C ++, a cosa unsigned charserve un? In che cosa differisce da un normale char?
Risposte:
In C ++, ci sono tre tipi di caratteri distinti :
charsigned charunsigned charSe 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. sizeofsarebbe ancora segnalare la sua dimensione come1 - il che significa che si potrebbe avere sizeof (char) == sizeof (long) == 1.
sizeofperché non è una funzione ma un operatore. È uno stile ancora migliore omettere la parentesi quando si prende la dimensione di una variabile. sizeof *po 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 signedo unsigned, quindi è necessario richiedere esplicitamente signed charo unsigned charse l'implementazione dipende da esso. Utilizzalo solo charse intendi rappresentare i caratteri delle stringhe, poiché corrisponderanno a ciò che la tua piattaforma inserisce nella stringa.
La differenza tra signed chare unsigned charè come ti aspetteresti. Sulla maggior parte delle piattaforme, signed charsarà un numero di complemento di due bit a 8 bit che va da -128a 127e unsigned charsarà un numero intero senza segno a 8 bit ( 0a 255). Si noti che lo standard NON richiede che i chartipi abbiano 8 bit, solo quello sizeof(char)restituito 1. È possibile ottenere il numero di bit in un carattere con CHAR_BITin 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_te uint8_tse vuoi davvero rappresentare piccoli numeri interi.
CHAR_BITlo 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 charpartecipare nella determinazione del valore se qualsiasi oggetto char senza segno. In secondo luogo, unsigned charviene esplicitamente dichiarato non firmato.
Ora, ho avuto una discussione con qualcuno su cosa succede quando converti il valore -1di type int in unsigned char. Ha rifiutato l'idea che il risultato unsigned charabbia 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.3p2in 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 -1sono uno prima della conversione. Quindi, cosa abbiamo in modo da poter affermare che il risultato unsigned charha tutti i suoi CHAR_BITbit trasformati in 1?
UCHAR_MAX+1a si -1otterrà un valore nell'intervallo, vale a direUCHAR_MAXQuesto è abbastanza, in realtà! Quindi ogni volta che vuoi avere uno unsigned charcon 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. ~0non lo è.
int x = 1234e 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 00000000LSB viene prima di tutto. Ora parte principale. se io uso printf("%d" , *p). printfleggerà il primo byte 11010010solo l'output è -46ma 11010010è 210per 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 charviene 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 charvalori 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 charl'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 chararitmetica. Tuttavia, se i valori fossero signed chars (127, -128, -128), finiremmo con (-99, -99, -99), che sarebbe (29, 29, 29) nel nostro unsigned charspazio, il che non è corretto .
Se si desidera utilizzare un carattere come un intero piccolo, il modo più sicuro per farlo è con i tipi int8_te uint8_t.
int8_te uint8_tsono opzionali e non definiti su architetture in cui la dimensione dei byte non è esattamente di 8 bit. Viceversa, signed chare unsigned charsono sempre disponibili e in grado di conservare almeno 8 bit. Potrebbe essere un modo comune ma non il più sicuro .
signed chare unsigned char? O consiglieresti una migliore alternativa "più sicura" in quel caso particolare? Ad esempio, attenersi ai tipi interi "reali" signed inte unsigned intinvece per qualche motivo?
signed chare 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.
chare unsigned charnon è 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 charha 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 charin 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_MINe CHAR_MAXmentre 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 charsarà [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 chare 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 chardell'OR e quindi procedere utilizzando ++ptrda 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 chartipologie: 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 signedo unsignedpuò 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 chared unsigned charentrambi rappresentano 1 byte, ma hanno intervalli diversi.
Type | range
-------------------------------
signed char | -128 to +127
unsigned char | 0 to 255
In signed charse 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