Ci sono alcune ottime risposte qui, ma penso che ci siano un paio di cose che posso aggiungere riguardo a Windows / Visual Studio. Questa è basata sulla mia esperienza con VS2015. Su Linux, fondamentalmente la risposta è usare UTF-8 codificato std::string
ovunque. Su Windows / VS diventa più complesso. Ecco perché. Windows prevede che le stringhe memorizzate utilizzando char
s vengano codificate utilizzando la tabella codici locale. Questo è quasi sempre il set di caratteri ASCII seguito da altri 128 caratteri speciali a seconda della posizione. Vorrei solo affermare che questo non solo quando si utilizza l'API di Windows, ci sono altri tre luoghi principali in cui queste stringhe interagiscono con il C ++ standard. Si tratta di valori letterali di stringa, output per l' std::cout
utilizzo <<
e il passaggio di un nome file astd::fstream
.
Sarò qui di fronte che sono un programmatore, non uno specialista delle lingue. Apprezzo che USC2 e UTF-16 non siano uguali, ma per i miei scopi sono abbastanza vicini da essere intercambiabili e li uso come tali qui. In realtà non sono sicuro di quale Windows utilizzi, ma in genere non ho nemmeno bisogno di sapere. Ho dichiarato UCS2 in questa risposta, quindi scusami in anticipo se ho turbato qualcuno con la mia ignoranza su questa faccenda e sono felice di cambiarla se ho qualcosa di sbagliato.
Letterali a corda
Se inserisci valori letterali stringa che contengono solo caratteri che possono essere rappresentati dalla tua tabella codici, VS li memorizza nel tuo file con 1 byte per codifica dei caratteri in base alla tua tabella codici. Nota che se cambi la tua tabella codici o dai la tua fonte a un altro sviluppatore usando una tabella codici diversa, penso (ma non ho testato) che il personaggio finirà per essere diverso. Se esegui il codice su un computer utilizzando una tabella codici diversa, non sono sicuro che anche il personaggio cambierà.
Se inserisci valori letterali stringa che non possono essere rappresentati dalla tua tabella codici, VS ti chiederà di salvare il file come Unicode. Il file verrà quindi codificato come UTF-8. Ciò significa che tutti i caratteri non ASCII (compresi quelli presenti nella tua tabella codici) saranno rappresentati da 2 o più byte. Ciò significa che se dai la tua fonte a qualcun altro, la fonte avrà lo stesso aspetto. Tuttavia, prima di passare l'origine al compilatore, VS converte il testo codificato UTF-8 nel testo codificato della tabella codici e tutti i caratteri mancanti dalla tabella codici vengono sostituiti con ?
.
L'unico modo per garantire la corretta rappresentazione di un valore letterale stringa Unicode in VS è quello di precedere il valore letterale stringa L
rendendolo un valore letterale stringa ampio. In questo caso VS convertirà il testo codificato UTF-8 dal file in UCS2. È quindi necessario passare letteralmente questa stringa in un std::wstring
costruttore o convertirla in utf-8 e metterla in a std::string
. Oppure, se lo desideri, puoi utilizzare le funzioni dell'API di Windows per codificarlo utilizzando la tua tabella codici per inserirlo in a std::string
, ma potresti non aver usato una stringa letterale ampia.
std :: cout
Quando si esegue l'output alla console mediante <<
è possibile utilizzare solo std::string
, no std::wstring
e il testo deve essere codificato utilizzando la tabella codici locale. Se ne hai uno std::wstring
, devi convertirlo utilizzando una delle funzioni dell'API di Windows e tutti i caratteri non presenti nella tua tabella codici vengono sostituiti da ?
(forse puoi cambiare il carattere, non ricordo).
std :: nomi di file fstream
Il sistema operativo Windows utilizza UCS2 / UTF-16 per i suoi nomi di file, quindi qualunque sia la tua tabella codici, puoi avere file con qualsiasi carattere Unicode. Ciò significa che per accedere o creare file con caratteri non presenti nella tabella codici è necessario utilizzare std::wstring
. Non c'è altro modo. Questa è un'estensione specifica di Microsoft, std::fstream
quindi probabilmente non verrà compilata su altri sistemi. Se usi std :: string, puoi utilizzare solo nomi di file che includono solo caratteri nella tua tabella codici.
Le tue opzioni
Se stai solo lavorando su Linux, probabilmente non sei arrivato così lontano. Usa UTF-8 std::string
ovunque.
Se stai solo lavorando su Windows, usa UCS2 std::wstring
ovunque. Alcuni puristi potrebbero dire che utilizzare UTF8 e poi convertirli quando necessario, ma perché preoccuparsi della seccatura.
Se sei multipiattaforma, allora è un casino essere sincero. Se si tenta di utilizzare UTF-8 ovunque su Windows, è necessario prestare molta attenzione ai valori letterali delle stringhe e all'output sulla console. Puoi facilmente corrompere le tue corde lì. Se usi std::wstring
ovunque su Linux, potresti non avere accesso alla versione estesa di std::fstream
, quindi devi fare la conversione, ma non c'è rischio di corruzione. Quindi personalmente penso che questa sia un'opzione migliore. Molti non sarebbero d'accordo, ma io non sono solo - è il percorso intrapreso da wxWidgets per esempio.
Un'altra opzione potrebbe essere quella di digitare unicodestring
come std::string
su Linux e std::wstring
su Windows e avere una macro chiamata UNI () che prefigura L su Windows e nulla su Linux, quindi il codice
#include <fstream>
#include <string>
#include <iostream>
#include <Windows.h>
#ifdef _WIN32
typedef std::wstring unicodestring;
#define UNI(text) L ## text
std::string formatForConsole(const unicodestring &str)
{
std::string result;
//Call WideCharToMultiByte to do the conversion
return result;
}
#else
typedef std::string unicodestring;
#define UNI(text) text
std::string formatForConsole(const unicodestring &str)
{
return str;
}
#endif
int main()
{
unicodestring fileName(UNI("fileName"));
std::ofstream fout;
fout.open(fileName);
std::cout << formatForConsole(fileName) << std::endl;
return 0;
}
andrebbe bene su entrambe le piattaforme credo.
risposte
Quindi, per rispondere alle tue domande
1) Se stai programmando per Windows, quindi sempre, se multipiattaforma, forse sempre, a meno che tu non voglia affrontare eventuali problemi di corruzione su Windows o scrivere un codice con una piattaforma specifica #ifdefs
per aggirare le differenze, se stai semplicemente usando Linux quindi mai.
2) Sì. Inoltre su Linux puoi usarlo anche per tutti gli Unicode. Su Windows puoi usarlo per tutti gli Unicode se scegli di codificare manualmente usando UTF-8. Ma l'API di Windows e le classi C ++ standard si aspettano std::string
che vengano codificate utilizzando la tabella codici locale. Ciò include tutte le ASCII più altri 128 caratteri che cambiano a seconda della tabella codici che il computer è configurato per l'uso.
3) Credo di sì, ma in caso contrario si tratta solo di un semplice typedef di un 'std :: basic_string' che utilizza wchar_t
invece dichar
4) Un carattere largo è un tipo di carattere più grande del char
tipo standard a 1 byte . Su Windows è di 2 byte, su Linux è di 4 byte.