Cos'è wchar_t?
wchar_t è definito in modo tale che la codifica char di qualsiasi locale possa essere convertita in una rappresentazione wchar_t dove ogni wchar_t rappresenta esattamente un codepoint:
Il tipo wchar_t è un tipo distinto i cui valori possono rappresentare codici distinti per tutti i membri del set di caratteri estesi più grande specificato tra le impostazioni internazionali supportate (22.3.1).
- C ++ [basic.fundamental] 3.9.1 / 5
Ciò non richiede che wchar_t sia abbastanza grande da rappresentare simultaneamente qualsiasi carattere da tutte le impostazioni locali. Cioè, la codifica utilizzata per wchar_t può differire tra le lingue. Ciò significa che non è possibile convertire necessariamente una stringa in wchar_t utilizzando una locale e quindi riconvertirla in char utilizzando un'altra locale. 1
Poiché l'utilizzo di wchar_t come rappresentazione comune tra tutte le impostazioni locali sembra essere l'uso principale di wchar_t in pratica, potresti chiederti a cosa serve se non quello.
L'intento originale e lo scopo di wchar_t era quello di rendere semplice l'elaborazione del testo definendolo in modo tale da richiedere una mappatura uno-a-uno dalle unità di codice di una stringa ai caratteri del testo, consentendo così l'uso degli stessi semplici algoritmi utilizzati con stringhe ascii per lavorare con altri linguaggi.
Sfortunatamente la formulazione delle specifiche di wchar_t presuppone una mappatura uno-a-uno tra caratteri e punti di codice per ottenere ciò. Unicode infrange questa ipotesi 2 , quindi non puoi usare tranquillamente wchar_t per semplici algoritmi di testo.
Ciò significa che il software portatile non può utilizzare wchar_t né come rappresentazione comune del testo tra le impostazioni locali, né per abilitare l'uso di semplici algoritmi di testo.
A cosa serve wchar_t oggi?
Non molto, comunque per il codice portatile. Se __STDC_ISO_10646__
è definito, i valori di wchar_t rappresentano direttamente i punti di codice Unicode con gli stessi valori in tutte le impostazioni locali. Ciò rende sicuro eseguire le conversioni inter-locale menzionate in precedenza. Tuttavia non puoi fare affidamento solo su di esso per decidere che puoi usare wchar_t in questo modo perché, mentre la maggior parte delle piattaforme unix lo definisce, Windows non lo fa anche se Windows utilizza la stessa locale wchar_t in tutte le versioni locali.
Il motivo per cui Windows non definisce __STDC_ISO_10646__
è perché Windows utilizza UTF-16 come codifica wchar_t e poiché UTF-16 utilizza coppie surrogate per rappresentare punti di codice maggiori di U + FFFF, il che significa che UTF-16 non soddisfa i requisiti per __STDC_ISO_10646__
.
Per il codice specifico della piattaforma wchar_t potrebbe essere più utile. È essenzialmente richiesto su Windows (ad esempio, alcuni file semplicemente non possono essere aperti senza utilizzare i nomi di file wchar_t), sebbene Windows sia l'unica piattaforma in cui questo è vero per quanto ne so (quindi forse possiamo pensare a wchar_t come 'Windows_char_t').
Col senno di poi wchar_t non è chiaramente utile per semplificare la gestione del testo o come archivio per il testo indipendente dalla locale. Il codice portatile non dovrebbe tentare di usarlo per questi scopi. Il codice non portabile potrebbe trovarlo utile semplicemente perché alcune API lo richiedono.
Alternative
L'alternativa che mi piace è usare stringhe C codificate UTF-8, anche su piattaforme non particolarmente amichevoli verso UTF-8.
In questo modo è possibile scrivere codice portatile utilizzando una rappresentazione di testo comune su piattaforme, utilizzare tipi di dati standard per lo scopo previsto, ottenere il supporto del linguaggio per quei tipi (ad esempio stringhe letterali, sebbene alcuni trucchi siano necessari per farlo funzionare con alcuni compilatori), alcuni supporto delle librerie standard, supporto del debugger (potrebbero essere necessari più trucchi), ecc. Con caratteri larghi è generalmente più difficile o impossibile ottenere tutto questo e potresti ottenere pezzi diversi su piattaforme diverse.
Una cosa che UTF-8 non fornisce è la possibilità di utilizzare semplici algoritmi di testo come sono possibili con ASCII. In questo UTF-8 non è peggiore di qualsiasi altra codifica Unicode. In effetti può essere considerato migliore perché le rappresentazioni di unità multi-codice in UTF-8 sono più comuni e quindi è più probabile che i bug nel codice che gestiscono tali rappresentazioni di caratteri a larghezza variabile vengano notati e corretti rispetto a se si tenta di attenersi a UTF -32 con NFC o NFKC.
Molte piattaforme utilizzano UTF-8 come codifica char nativa e molti programmi non richiedono alcuna elaborazione significativa del testo, quindi scrivere un programma internazionalizzato su quelle piattaforme è leggermente diverso dalla scrittura di codice senza considerare l'internazionalizzazione. Scrivere codice più ampiamente portabile o scrivere su altre piattaforme richiede l'inserimento di conversioni ai confini delle API che utilizzano altre codifiche.
Un'altra alternativa utilizzata da alcuni software è quella di scegliere una rappresentazione multipiattaforma, come array brevi non firmati che contengono dati UTF-16, e quindi fornire tutto il supporto della libreria e semplicemente convivere con i costi del supporto linguistico, ecc.
C ++ 11 aggiunge nuovi tipi di caratteri larghi come alternative a wchar_t, char16_t e char32_t con funzioni di linguaggio / libreria associate. In realtà non è garantito che siano UTF-16 e UTF-32, ma non immagino che nessuna implementazione principale utilizzerà nient'altro. C ++ 11 migliora anche il supporto UTF-8, ad esempio con i valori letterali di stringa UTF-8, quindi non sarà necessario ingannare VC ++ nella produzione di stringhe codificate UTF-8 (anche se posso continuare a farlo piuttosto che usare il u8
prefisso) .
Alternative da evitare
TCHAR: TCHAR è per la migrazione di vecchi programmi Windows che assumono codifiche legacy da char a wchar_t, ed è meglio dimenticarlo a meno che il tuo programma non sia stato scritto in qualche millennio precedente. Non è portabile ed è intrinsecamente non specifico riguardo alla sua codifica e persino al suo tipo di dati, rendendolo inutilizzabile con qualsiasi API non basata su TCHAR. Poiché il suo scopo è la migrazione a wchar_t, che abbiamo visto sopra non è una buona idea, non c'è alcun valore nell'usare TCHAR.
1. I caratteri che sono rappresentabili nelle stringhe wchar_t ma che non sono supportati in nessuna locale non devono essere rappresentati con un singolo valore wchar_t. Ciò significa che wchar_t potrebbe utilizzare una codifica a larghezza variabile per determinati caratteri, un'altra chiara violazione dell'intento di wchar_t. Sebbene sia discutibile che un carattere rappresentabile da wchar_t sia sufficiente per dire che la locale "supporta" quel carattere, nel qual caso le codifiche a larghezza variabile non sono legali e l'uso di UTF-16 da parte di Window non è conforme.
2. Unicode consente di rappresentare molti caratteri con più punti di codice, il che crea gli stessi problemi per semplici algoritmi di testo delle codifiche a larghezza variabile. Anche se si mantiene rigorosamente una normalizzazione composta, alcuni caratteri richiedono ancora più punti di codice. Vedi: http://www.unicode.org/standard/where/