Perché gli stream C ++ utilizzano char invece di char unsigned?

Mi sono sempre chiesto perché la libreria Standard C ++ abbia istanziato il stream di base_ [io] e tutte le sue varianti usando il tipo di char anziché il tipo di unsigned char . char significa (a seconda che sia firmato o meno) è ansible avere overflow e underflow per operazioni come get (), che porteranno al valore definito dall’implementazione delle variabili coinvolte. Un altro esempio è quando vuoi esportare un byte, non formattato, in un ostream usando la sua funzione put .

Qualche idea?


Nota : non sono ancora veramente convinto. Quindi se conosci la risposta definitiva, puoi comunque postarla davvero.

Forse ho frainteso la domanda, ma la conversione da char non formattato a char non è non specificata, dipende dall’implementazione (4.7-3 nello standard C ++).

Il tipo di carattere a 1 byte in C ++ è “char”, non “unsigned char”. Ciò dà alle implementazioni un po ‘più di libertà di fare la cosa migliore sulla piattaforma (ad esempio, il corpo degli standard potrebbe aver creduto che esistano CPU in cui l’aritmetica dei byte firmati è più veloce dell’aritmetica dei byte senza segno, anche se è una speculazione da parte mia). Anche per compatibilità con C. Il risultato di rimuovere questo tipo di incertezza esistenziale da C ++ è C # 😉

Dato che il tipo “char” esiste, penso che abbia senso per i soliti flussi usarlo anche se la sua firma non è definita. Quindi forse alla tua domanda viene data risposta dalla risposta a “perché il C ++ non ha appena definito il char come non firmato?”

L’ho sempre capito in questo modo: lo scopo della class iostream è leggere e / o scrivere un stream di caratteri che, se ci pensate, sono entity framework astratte che sono rappresentate solo dal computer usando una codifica di caratteri. Lo standard C ++ fa molto fatica a evitare di codificare la codifica del personaggio, dicendo solo che “Gli oggetti dichiarati come caratteri ( char ) devono essere abbastanza grandi da contenere qualsiasi membro del set di caratteri di base dell’implementazione”, perché non ha bisogno di forzare “implementazione del set di caratteri di base” per definire il linguaggio C ++; lo standard può lasciare la decisione su quale codifica dei caratteri viene utilizzata per l’implementazione (compilatore insieme con un’implementazione STL), e solo notare che gli oggetti char rappresentano singoli caratteri in alcune codifiche.

Uno scrittore di implementazione può scegliere una codifica a ottetto singolo come ISO-8859-1 o anche una codifica a doppio ottetto come UCS-2 . Non importa. Finché un object char è “abbastanza grande da memorizzare qualsiasi membro del set di caratteri di base dell’implementazione” (si noti che questo vieta espressamente le codifiche a lunghezza variabile ), quindi l’implementazione può anche scegliere una codifica che rappresenta il latino di base in un modo che è incompatibile con qualsiasi codifica comune!

È confuso che i char , signed char e unsigned char condividano “char” nei loro nomi, ma è importante tenere presente che char non appartiene alla stessa famiglia di tipi fondamentali come signed char unsigned char e unsigned char . signed char è nella famiglia dei tipi interi con signed char :

Esistono quattro tipi di interi con segno: “signed char”, “short int”, “int” e “long int”.

e il unsigned char trova nella famiglia di tipi interi senza segno:

Per ciascuno dei tipi di interi con segno , esiste un corrispondente (ma diverso) tipo di intero senza segno : “unsigned char”, “unsigned short int”, “unsigned int” e “unsigned long int”, …

L’unica somiglianza tra i char , signed char e unsigned char è che “[essi] occupano la stessa quantità di storage e hanno gli stessi requisiti di allineamento”. Pertanto, è ansible reinterpret_cast da char * a unsigned char * per determinare il valore numerico di un carattere nel set di caratteri di esecuzione.

Per rispondere alla tua domanda, il motivo per cui STL usa char come tipo predefinito è perché gli stream standard sono pensati per leggere e / o scrivere flussi di caratteri, rappresentati da oggetti char , non interi ( signed char e unsigned char ). L’uso del char rispetto al valore numerico è un modo per separare le preoccupazioni.

char è per caratteri, char unsigned per byte grezzi di dati e caratteri firmati per, beh, dati firmati.

Lo standard non specifica se verrà utilizzato il char firmato o non firmato per l’implementazione di char – è specifico del compilatore. Specifica solo che il “char” sarà “sufficiente” per contenere i caratteri sul sistema dell’utente – il modo in cui i personaggi si trovavano in quei giorni, ovvero UNICODE.

Usare “char” per i caratteri è il modo standard per andare. L’uso di unsigned char è un hack, sebbene corrisponda all’implementazione di char del compilatore sulla maggior parte delle piattaforms.

Penso che questo commento lo spieghi bene. Per citare:

il char firmato e il char unsigned sono aritmetici, tipi interi come int e unsigned int. D’altra parte, char è espressamente inteso come il tipo di “I / O” che rappresenta una unità di dati opaca e specifica del sistema sulla tua piattaforma. Li userei in questo spirito.