Il y a de très bonnes réponses ici, mais je pense qu'il y a quelques choses que je peux ajouter concernant Windows / Visual Studio. C'est basé sur mon expérience avec VS2015. Sous Linux, la solution consiste essentiellement à utiliser UTF-8 encodé std::string
partout. Sous Windows / VS, cela devient plus complexe. Voici pourquoi. Windows attend des chaînes stockées à l'aidechar
s soient encodées à l'aide de la page de codes locale. Il s'agit presque toujours du jeu de caractères ASCII suivi de 128 autres caractères spéciaux selon votre emplacement. Permettez-moi de préciser que cela ne se produit pas uniquement lors de l'utilisation de l'API Windows, il existe trois autres endroits majeurs où ces chaînes interagissent avec le C ++ standard. Ce sont des littéraux de chaîne, sortis en std::cout
utilisant <<
et en passant un nom de fichier àstd::fstream
.
Je dirai ici que je suis programmeur, pas spécialiste des langues. J'apprécie que USC2 et UTF-16 ne sont pas les mêmes, mais à mes fins, ils sont suffisamment proches pour être interchangeables et je les utilise comme tels ici. Je ne sais pas vraiment quel Windows utilise, mais je n'ai généralement pas besoin de le savoir non plus. J'ai indiqué UCS2 dans cette réponse, donc désolé à l'avance si je contrarie quelqu'un avec mon ignorance de cette question et je suis heureux de le changer si je me trompe.
Littéraux de chaîne
Si vous entrez des littéraux de chaîne qui ne contiennent que des caractères pouvant être représentés par votre page de code, VS les stocke dans votre fichier avec un codage de 1 octet par caractère basé sur votre page de code. Notez que si vous changez votre page de code ou donnez votre source à un autre développeur en utilisant une page de code différente, je pense (mais je n'ai pas testé) que le personnage finira différent. Si vous exécutez votre code sur un ordinateur en utilisant une page de codes différente, je ne sais pas si le caractère changera également.
Si vous entrez des littéraux de chaîne qui ne peuvent pas être représentés par votre page de code, VS vous demandera d'enregistrer le fichier en Unicode. Le fichier sera ensuite encodé en UTF-8. Cela signifie que tous les caractères non ASCII (y compris ceux qui se trouvent sur votre page de code) seront représentés par 2 octets ou plus. Cela signifie que si vous donnez votre source à quelqu'un d'autre, la source sera la même. Cependant, avant de transmettre la source au compilateur, VS convertit le texte codé UTF-8 en texte codé de page de code et tous les caractères manquants de la page de code sont remplacés par?
.
La seule façon de garantir une représentation correcte d'un littéral de chaîne Unicode dans VS est de faire précéder le littéral de chaîne d'un en L
faisant un littéral de chaîne large. Dans ce cas, VS convertira le texte encodé UTF-8 du fichier en UCS2. Vous devez ensuite passer ce littéral de chaîne dans un std::wstring
constructeur ou vous devez le convertir en utf-8 et le mettre dans a std::string
. Ou si vous le souhaitez, vous pouvez utiliser les fonctions de l'API Windows pour l'encoder en utilisant votre page de codes pour le mettre dans unstd::string
, mais vous pouvez aussi ne pas avoir utilisé un littéral de chaîne large.
std :: cout
Lors de la sortie vers la console à l'aide de, <<
vous pouvez uniquement utiliser std::string
, non std::wstring
et le texte doit être codé à l'aide de votre page de code locale. Si vous en avez un, std::wstring
vous devez le convertir à l'aide de l'une des fonctions de l'API Windows et tous les caractères ne figurant pas sur votre page de code seront remplacés par ?
(vous pouvez peut-être changer le caractère, je ne me souviens pas).
std :: fstream noms de fichiers
Le système d'exploitation Windows utilise UCS2 / UTF-16 pour ses noms de fichiers, quelle que soit votre page de code, vous pouvez avoir des fichiers avec n'importe quel caractère Unicode. Mais cela signifie que pour accéder ou créer des fichiers avec des caractères ne figurant pas sur votre page de code, vous devez utiliser std::wstring
. Il n'y a pas d'autre moyen. Il s'agit d'une extension spécifique à Microsoft std::fstream
qui ne se compilera donc probablement pas sur d'autres systèmes. Si vous utilisez std :: string, vous ne pouvez utiliser que des noms de fichiers qui incluent uniquement des caractères sur votre page de code.
Vos options
Si vous travaillez uniquement sur Linux, vous n'êtes probablement pas allé aussi loin. Utilisez simplement UTF-8 std::string
partout.
Si vous travaillez uniquement sur Windows, utilisez simplement UCS2 std::wstring
partout. Certains puristes peuvent dire utiliser UTF8 puis convertir au besoin, mais pourquoi s'embêter avec les tracas.
Si vous êtes multiplateforme, c'est un gâchis d'être franc. Si vous essayez d'utiliser UTF-8 partout sur Windows, vous devez être très prudent avec vos littéraux de chaîne et la sortie vers la console. Vous pouvez facilement y corrompre vos chaînes. Si vous utilisez std::wstring
partout sur Linux, vous n'aurez peut-être pas accès à la version large de std::fstream
, vous devez donc effectuer la conversion, mais il n'y a aucun risque de corruption. Personnellement, je pense que c'est une meilleure option. Beaucoup seraient en désaccord, mais je ne suis pas seul - c'est le chemin emprunté par wxWidgets par exemple.
Une autre option pourrait être de taper unicodestring
comme std::string
sous Linux et std::wstring
sous Windows, et d'avoir une macro appelée UNI () qui préfixe L sous Windows et rien sous Linux, puis le code
#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;
}
serait bien sur l'une ou l'autre plate-forme, je pense.
Réponses
Alors pour répondre à vos questions
1) Si vous programmez pour Windows, alors tout le temps, si multiplateforme, peut-être tout le temps, à moins que vous ne vouliez faire face à d'éventuels problèmes de corruption sur Windows ou écrire du code avec une plate-forme spécifique #ifdefs
pour contourner les différences, si vous utilisez simplement Linux alors jamais.
2) Oui. De plus, sous Linux, vous pouvez également l'utiliser pour tous les Unicode. Sous Windows, vous ne pouvez l'utiliser pour tous les Unicode que si vous choisissez de coder manuellement en utilisant UTF-8. Mais l'API Windows et les classes C ++ standard s'attendent std::string
à ce qu'elles soient encodées à l'aide de la page de codes locale. Cela inclut tous les caractères ASCII et 128 autres caractères qui changent en fonction de la page de codes que votre ordinateur est configuré pour utiliser.
3) Je le crois, mais sinon, ce n'est qu'un simple typedef d'un 'std :: basic_string' utilisant wchar_t
au lieu dechar
4) Un caractère large est un type de caractère plus grand que le char
type standard à 1 octet . Sous Windows, il est de 2 octets, sous Linux, il est de 4 octets.