web-dev-qa-db-fra.com

std :: wstring VS std :: string

Je ne suis pas en mesure de comprendre les différences entre std::string et std::wstring. Je sais que wstring prend en charge les caractères larges tels que les caractères Unicode. J'ai les questions suivantes:

  1. Quand devrais-je utiliser std::wstring sur std::string?
  2. std::string peut-il contenir tout le jeu de caractères ASCII, y compris les caractères spéciaux?
  3. std::wstring est-il supporté par tous les compilateurs C++ populaires?
  4. Quel est exactement un " caractère large "?
673
Appu

string? wstring?

_std::string_ est un basic_string basé sur un char, et _std::wstring_ sur un wchar_t .

char vs. _wchar_t_

char est supposé contenir un caractère, généralement un caractère de 8 bits.
_wchar_t_ est supposé contenir un caractère large, et ensuite, les choses deviennent difficiles:
Sous Linux, un _wchar_t_ correspond à 4 octets, tandis que sous Windows, il s'agit de 2 octets.

Qu'en est-il de nicode , alors?

Le problème est que ni char, ni _wchar_t_ n'est directement lié à unicode.

Sur Linux?

Prenons un système d'exploitation Linux: Mon système Ubuntu est déjà compatible Unicode. Lorsque je travaille avec une chaîne de caractères, celle-ci est encodée de manière native dans le format TF-8 (c'est-à-dire une chaîne de caractères Unicode). Le code suivant:

_#include <cstring>
#include <iostream>

int main(int argc, char* argv[])
{
   const char text[] = "olé" ;


   std::cout << "sizeof(char)    : " << sizeof(char) << std::endl ;
   std::cout << "text            : " << text << std::endl ;
   std::cout << "sizeof(text)    : " << sizeof(text) << std::endl ;
   std::cout << "strlen(text)    : " << strlen(text) << std::endl ;

   std::cout << "text(ordinals)  :" ;

   for(size_t i = 0, iMax = strlen(text); i < iMax; ++i)
   {
      std::cout << " " << static_cast<unsigned int>(
                              static_cast<unsigned char>(text[i])
                          );
   }

   std::cout << std::endl << std::endl ;

   // - - - 

   const wchar_t wtext[] = L"olé" ;

   std::cout << "sizeof(wchar_t) : " << sizeof(wchar_t) << std::endl ;
   //std::cout << "wtext           : " << wtext << std::endl ; <- error
   std::cout << "wtext           : UNABLE TO CONVERT NATIVELY." << std::endl ;
   std::wcout << L"wtext           : " << wtext << std::endl;

   std::cout << "sizeof(wtext)   : " << sizeof(wtext) << std::endl ;
   std::cout << "wcslen(wtext)   : " << wcslen(wtext) << std::endl ;

   std::cout << "wtext(ordinals) :" ;

   for(size_t i = 0, iMax = wcslen(wtext); i < iMax; ++i)
   {
      std::cout << " " << static_cast<unsigned int>(
                              static_cast<unsigned short>(wtext[i])
                              );
   }

   std::cout << std::endl << std::endl ;

   return 0;
}
_

affiche le texte suivant:

_sizeof(char)    : 1
text            : olé
sizeof(text)    : 5
strlen(text)    : 4
text(ordinals)  : 111 108 195 169

sizeof(wchar_t) : 4
wtext           : UNABLE TO CONVERT NATIVELY.
wtext           : ol�
sizeof(wtext)   : 16
wcslen(wtext)   : 3
wtext(ordinals) : 111 108 233
_

Vous verrez que le texte "olé" dans char est réellement composé de quatre caractères: 110, 108, 195 et 169 (sans compter le zéro final). (Je vous laisserai étudier le code _wchar_t_ comme exercice)

Ainsi, lorsque vous travaillez avec un char sur Linux, vous devez généralement utiliser Unicode sans même le savoir. Et comme _std::string_ fonctionne avec char, donc _std::string_ est déjà prêt pour Unicode.

Notez que _std::string_, comme l’API de chaîne C, considérera que la chaîne "olé" a 4 caractères, pas trois. Vous devriez donc faire preuve de prudence lorsque vous tronquez/jouez avec des caractères Unicode, car une combinaison de caractères est interdite dans UTF-8.

Sur Windows?

Sous Windows, c'est un peu différent. Win32 devait prendre en charge de nombreuses applications travaillant avec char et sur différents jeux de caractères / pages de codes produits dans le monde entier, avant l'avènement de l'Unicode.

Leur solution était donc intéressante: si une application fonctionne avec char, alors les chaînes de caractères sont codées/imprimées/affichées sur les étiquettes de l'interface graphique à l'aide du jeu de caractères/de la page de code local sur la machine. Par exemple, "olé" serait "olé" dans un Windows localisé en français, mais serait différent dans un Windows à localisation cyrillique ("olé" si vous utilisez Windows-1251 ). Ainsi, les "applications historiques" continueront généralement à fonctionner de la même manière.

Pour les applications basées sur Unicode, Windows utilise _wchar_t_, large de 2 octets et codé en TF-16 , codé en Unicode sur des caractères de 2 octets (ou tout au moins , la plupart du temps compatible UCS-2, qui est presque la même chose IIRC).

Les applications utilisant char sont dites "multi-octets" (car chaque glyphe est composé d'un ou plusieurs chars), tandis que les applications utilisant _wchar_t_ sont appelées "widechar" (car chaque glyphe est composé d'un ou deux _wchar_t_. Voir MultiByteToWideChar et WideCharToMultiByte API de conversion Win32 pour plus d'informations.

Ainsi, si vous travaillez sous Windows, vous désirez absolument utiliser _wchar_t_ (sauf si vous utilisez un cadre masquant cela, comme GTK + ou QT ...). En coulisse, Windows fonctionne avec les chaînes _wchar_t_. Ainsi, même les applications historiques verront leurs chaînes char converties en _wchar_t_ lors de l’utilisation d’une API comme SetWindowText() (niveau bas). Fonction API pour définir l’étiquette sur une interface graphique Win32).

Problèmes de mémoire?

UTF-32 correspond à 4 octets par caractères. Il n’ya donc pas grand chose à ajouter, si seulement le texte UTF-8 et le texte UTF-16 utilisent toujours moins ou la même quantité de mémoire que le texte UTF-32 (et généralement moins ).

En cas de problème de mémoire, sachez que pour la plupart des langues occidentales, le texte UTF-8 utilise moins de mémoire que le même en UTF-16.

Néanmoins, pour les autres langues (chinois, japonais, etc.), la mémoire utilisée sera la même ou légèrement plus grande pour UTF-8 que pour UTF-16.

Au total, UTF-16 utilisera principalement 2 et parfois 4 octets par caractères (sauf si vous avez affaire à une sorte de glyphes en langue ésotérique (Klingon? Elfique?), Tandis que UTF-8 utilisera entre 1 et 4 octets.

Voir http://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16 pour plus d'informations.

Conclusion

  1. Quand dois-je utiliser std :: wstring sur std :: string?

    Sur Linux? Presque jamais (§).
    Sous Windows? Presque toujours (§).
    Sur du code multiplateforme? Cela dépend de votre boîte à outils ...

    (§): sauf si vous utilisez un toolkit/framework disant le contraire

  2. Est-ce que _std::string_ peut contenir tout le jeu de caractères ASCII, y compris les caractères spéciaux?

    Remarque: Un _std::string_ convient pour contenir un tampon 'binaire', alors qu'un _std::wstring_ ne l'est pas!

    Sur Linux? Oui.
    Sous Windows? Seuls les caractères spéciaux disponibles pour l'environnement local actuel de l'utilisateur Windows.

    Modifier (Après un commentaire de Johann Gerell ):
    a _std::string_ suffira à gérer toutes les chaînes basées sur char (chaque char représentant un nombre compris entre 0 et 255). Mais:

    1. ASCII est supposé aller de 0 à 127. Higher chars ne sont pas ASCII.
    2. un char de 0 à 127 sera tenu correctement
    3. a char entre 128 et 255 aura une signification en fonction de votre encodage (unicode, non-unicode, etc.), mais il pourra contenir tous les glyphes Unicode tant qu'ils sont encodés en UTF-8.
  3. Est-ce que _std::wstring_ est pris en charge par presque tous les compilateurs C++ populaires?

    Principalement, à l'exception des compilateurs basés sur GCC et portés sur Windows.
    Cela fonctionne sur mon g ++ 4.3.2 (sous Linux), et j’utilisais l’API Unicode sur Win32 depuis Visual C++ 6.

  4. Qu'est-ce qu'un caractère large?

    En C/C++, il s'agit d'un type de caractère écrit _wchar_t_ qui est supérieur au type de caractère simple char. Il est supposé être utilisé pour insérer à l'intérieur des caractères dont les index (tels que les glyphes Unicode) sont supérieurs à 255 (ou 127, selon ...).

955
paercebal

Je recommande d'éviter std::wstring sous Windows ou ailleurs, sauf lorsque cela est requis par l'interface ou à proximité d'appels API Windows et de conversions de codage respectives comme un sucre syntaxique. 

Mon point de vue est résumé dans http://utf8everywhere.org dont je suis co-auteur. 

Sauf si votre application est centrée sur les appels API, par ex. principalement application, la suggestion est de stocker les chaînes Unicode dans std :: string et encodées en UTF-8, en effectuant la conversion à proximité des appels API. Les avantages décrits dans l'article l'emportent sur les inconvénients apparents de la conversion, en particulier dans les applications complexes. C'est le cas doublement pour le développement multiplateforme et en bibliothèque. 

Et maintenant, répondez à vos questions:

  1. Quelques raisons faibles. Il existe pour des raisons historiques, où les widechars étaient considérés comme le moyen approprié de prendre en charge Unicode. Il est maintenant utilisé pour interfacer les API qui préfèrent les chaînes UTF-16. Je ne les utilise que dans le voisinage direct de tels appels API.
  2. Cela n'a rien à voir avec std :: string. Il peut contenir tout l'encodage que vous y mettez. La seule question est de savoir comment Vous traitez son contenu. Ma recommandation est UTF-8, de sorte qu'il puisse contenir tous les caractères Unicode correctement. C'est une pratique courante sous Linux, mais je pense que les programmes Windows devraient également le faire.
  3. Non. 
  4. Caractère large est un nom déroutant. Aux débuts de l'Unicode, on croyait qu'un caractère pouvait être codé sur deux octets, d'où son nom. Aujourd'hui, cela signifie "toute partie du caractère longue de deux octets". UTF-16 est vu comme une séquence de telles paires d'octets (aka caractères larges). Un personnage dans UTF-16 prend une ou deux paires.
54
Pavel Radzivilovsky

Ainsi, chaque lecteur ici présent devrait avoir une compréhension claire des faits, de la situation. Sinon, alors vous devez lire la réponse remarquablement complète de paercebal} [btw: merci!].

Ma conclusion pragmatique est d'une simplicité déconcertante: tout ce que "l'encodage de caractères" C++ (et STL) est substantiellement cassé et inutile. Blame it on Microsoft ou pas, ça n’aidera pas de toute façon.

Ma solution, après une enquête approfondie, beaucoup de frustration et les expériences qui en découlent est la suivante:

  1. acceptez le fait que vous devez assumer vous-même la responsabilité de l'encodage et de la conversion (et vous verrez qu'une grande partie est plutôt triviale)

  2. utilisez std :: string pour toutes les chaînes encodées en UTF-8 (juste un typedef std::string UTF8String)

  3. accepter qu'un tel objet UTF8String soit juste un conteneur idiot, mais bon marché. Ne jamais accéder et/ou manipuler des caractères directement dans celui-ci (pas de recherche, remplacement, etc.). Vous pouvez le faire, mais vous ne voulez vraiment pas perdre votre temps à écrire des algorithmes de manipulation de texte pour des chaînes multi-octets! Même si d'autres personnes ont déjà fait des choses aussi stupides, ne le faites pas! Laisse faire! (Eh bien, il y a des scénarios où cela a du sens ... utilisez simplement la bibliothèque ICU pour ceux-là).

  4. utilisez std :: wstring pour les chaînes codées UCS-2 (typedef std::wstring UCS2String) - il s'agit d'un compromis et d'une concession au désordre introduit par l'API WIN32). UCS-2 est suffisant pour la plupart d'entre nous (plus sur cela plus tard ...).

  5. utilisez des instances UCS2String lorsqu'un accès caractère par caractère est requis (lecture, manipulation, etc.). Tout traitement basé sur des caractères doit être effectué dans une représentation NON multi-octets. C'est simple, rapide, facile.

  6. ajoutez deux fonctions utilitaires pour la conversion entre UTF-8 et UCS-2:

    UCS2String ConvertToUCS2( const UTF8String &str );
    UTF8String ConvertToUTF8( const UCS2String &str );
    

Les conversions sont simples, google devrait aider ici ...

C'est tout. Utilisez UTF8String partout où la mémoire est précieuse et pour toutes les E/S UTF-8. Utilisez UCS2String partout où la chaîne doit être analysée et/ou manipulée. Vous pouvez convertir entre ces deux représentations à tout moment.

Alternatives et améliorations

  • des conversions de & en codages de caractères codés sur un octet (par exemple, ISO-8859-1) peuvent être réalisées à l'aide de tables de traduction en clair, par exemple. const wchar_t tt_iso88951[256] = {0,1,2,...}; et le code approprié pour la conversion vers et depuis UCS2.

  • si UCS-2 n'est pas suffisant, passez à UCS-4 (typedef std::basic_string<uint32_t> UCS2String)

ICU ou d'autres bibliothèques Unicode? _

Pour des choses avancées.

36
Frunsi
  1. Lorsque vous voulez avoir des caractères larges stockés dans votre chaîne. wide dépend de l'implémentation. Si je me souviens bien, Visual C++ utilise 16 bits par défaut, tandis que GCC utilise les valeurs par défaut en fonction de la cible. C'est 32 bits de long ici. Veuillez noter que wchar_t (type de caractère large) n'a rien à voir avec unicode. Il est simplement garanti qu'il peut stocker tous les membres du plus grand jeu de caractères pris en charge par l'implémentation par ses paramètres régionaux, et au moins aussi longtemps que char. Vous pouvez stocker des chaînes unicodes dans std::string en utilisant également le codage utf-8. Mais il ne comprendra pas la signification des points de code Unicode. Donc, str.size() ne vous donnera pas la quantité de caractères logiques dans votre chaîne, mais simplement la quantité d'éléments char ou wchar_t stockés dans cette chaîne/wstring. Pour cette raison, les responsables de wrapper gtk/glib C++ ont développé une classe Glib::ustring qui peut gérer utf-8. 

    Si votre wchar_t a une longueur de 32 bits, vous pouvez utiliser utf-32 comme codage Unicode et vous pouvez stocker et gérer les chaînes Unicode à l'aide d'un codage fixe (utf-32 est une longueur fixe). Cela signifie que la fonction s.size() de votre wstring alors renverra la bonne quantité d'éléments wchar_t et de caractères logiques. 

  2. Oui, char est toujours long d'au moins 8 bits, ce qui signifie qu'il peut stocker toutes les valeurs ASCII. 
  3. Oui, tous les principaux compilateurs le soutiennent.
25

J'utilise fréquemment std :: string pour contenir les caractères utf-8 sans aucun problème. Je recommande vivement de le faire lors de l'interfaçage avec des API qui utilisent également utf-8 comme type de chaîne natif.

Par exemple, j'utilise utf-8 lors de l'interfaçage de mon code avec l'interpréteur Tcl.

La mise en garde majeure est la longueur de std :: string, n'est plus le nombre de caractères de la chaîne.

5
Juan
  1. Lorsque vous souhaitez stocker des caractères "larges" (Unicode).
  2. Oui: 255 d'entre eux (sauf 0).
  3. Oui.
  4. Voici un article d'introduction: http://www.joelonsoftware.com/articles/Unicode.html
3
ChrisW

Les applications qui ne sont pas satisfaites avec seulement 256 caractères différents ont la possibilité d'utiliser des caractères larges (plus de 8 bits) ou un codage de longueur variable (un codage multi-octets en terminologie C++) tel que UTF-8. Les caractères larges nécessitent généralement plus d'espace qu'un codage de longueur variable, mais sont plus rapides à traiter. Les applications multilingues qui traitent de grandes quantités de texte utilisent généralement des caractères larges lors du traitement du texte, mais les convertissent au format UTF-8 lors de leur stockage sur disque.

La seule différence entre string et wstring réside dans le type de données des caractères stockés. Une chaîne stocke chars dont la taille est garantie à au moins 8 bits. Vous pouvez donc utiliser des chaînes pour le traitement, par exemple. Texte ASCII, ISO-8859-15 ou UTF-8. La norme ne dit rien sur le jeu de caractères ou l'encodage.

Pratiquement tous les compilateurs utilisent un jeu de caractères dont les 128 premiers caractères correspondent à ASCII. C'est également le cas des compilateurs utilisant le codage UTF-8. La chose importante à prendre en compte lors de l'utilisation de chaînes dans UTF-8 ou d'un autre codage à longueur variable, est que les index et les longueurs sont mesurés en octets et non en caractères.

Le type de données d'une chaîne wstring est wchar_t, dont la taille n'est pas définie dans la norme, sauf que sa taille doit être au moins égale à celle d'un caractère, généralement 16 ou 32 bits. wstring peut être utilisé pour traiter du texte dans le codage à caractères larges défini par l’implémentation. Comme l'encodage n'est pas défini dans la norme, la conversion entre chaînes et chaînes de caractères n'est pas simple. On ne peut pas non plus supposer que wstrings a un codage de longueur fixe.

Si vous n'avez pas besoin d'une prise en charge multilingue, vous pouvez utiliser uniquement des chaînes normales. Par contre, si vous écrivez une application graphique, il est fréquent que l'API ne prenne en charge que les caractères larges. Ensuite, vous souhaiterez probablement utiliser les mêmes caractères larges lors du traitement du texte. N'oubliez pas que UTF-16 est un codage de longueur variable, ce qui signifie que vous ne pouvez pas supposer que length() renvoie le nombre de caractères. Si l'API utilise un codage de longueur fixe, tel que UCS-2, le traitement devient facile. La conversion entre caractères larges et UTF-8 est difficile à faire de manière portable, mais là encore, votre API d'interface utilisateur prend probablement en charge la conversion.

2
Seppo Enarvi
  1. quand vous voulez utiliser des chaînes Unicode et pas seulement ascii, utile pour l'internationalisation
  2. oui, mais ça ne marche pas bien avec 0
  3. pas au courant de ceux qui ne le font pas
  4. caractère large est la manière spécifique du compilateur de gérer la représentation de longueur fixe d'un caractère unicode, pour MSVC, il s'agit d'un caractère de 2 octets, pour gcc, je comprends qu'il s'agit de 4 octets. et un +1 pour http://www.joelonsoftware.com/articles/Unicode.html
1
Greg Domjan

1) Comme l'a mentionné Greg, wstring est utile pour l'internationalisation. C'est à ce moment-là que votre produit sortira dans des langues autres que l'anglais.

4) Vérifiez ceci pour le caractère large http://en.wikipedia.org/wiki/Wide_character

0
Raghu

Une bonne question! Je pense que DATA ENCODING (parfois unCHARSETégalement impliqué) est un MEMORY EXPRESSION MECHANISM afin de sauvegarder des données dans un fichier ou de transférer des données via un réseau, alors je réponds à cette question comme:

1. Quand devrais-je utiliser std :: wstring sur std :: string?

Si la plate-forme de programmation ou la fonction API est mono-octet et que nous souhaitons traiter ou analyser des données Unicode, par exemple, lues à partir d'un fichier Windows.REG ou d'un flux réseau à 2 octets, nous devons déclarer facilement la variable std :: wstring les traiter. Exemple: wstring ws = L "中国 a" (mémoire de 6 octets: 0x4E2D 0x56FD 0x0061), nous pouvons utiliser ws [0] pour obtenir le caractère "中" et ws [1] pour obtenir le caractère "国" et ws [2] obtenir le caractère 'a', etc.

2. std :: string peut-il contenir tout le jeu de caractères ASCII, y compris les caractères spéciaux?

Oui. Mais remarquez que: ASCII américain signifie que chaque octet 0x00 ~ 0xFF représente un caractère, y compris un texte imprimable tel que "123abc & * _ &" et vous avez dit un caractère spécial, l’imprimez généralement comme un "." évitez de confondre les éditeurs ou les terminaux. Et certains autres pays développent leur propre jeu de caractères "ASCII", par exemple. Chinois, utilisez 2 octets pour représenter un caractère. 

3.Est-ce que std :: wstring est supporté par tous les compilateurs C++ populaires?

Peut-être, ou surtout. J'ai utilisé: VC++ 6 et GCC 3.3, OUI

4. Qu'est-ce qu'un "personnage large"?

un caractère large indique principalement l'utilisation de 2 octets ou de 4 octets pour contenir les caractères de tous les pays. 2 octets UCS2 est un échantillon représentatif, et par ex. Anglais 'a', sa mémoire est 2 octets de 0x0061 (vs dans ASCII 'la mémoire de a est 1 octet 0x61)

0
Leiyi.China

Il y a de très bonnes réponses ici, mais je pense pouvoir ajouter quelques points concernant Windows/Visual Studio. Ceci est basé sur mon expérience avec VS2015. Sous Linux, la solution consiste essentiellement à utiliser le std::string codé UTF-8 partout. Sous Windows/VS, cela devient plus complexe. Voici pourquoi. Windows s'attend à ce que les chaînes stockées à l'aide de chars soient codées à l'aide de la page de codes de paramètres régionaux. Il s’agit presque toujours du jeu de caractères ASCII suivi de 128 autres caractères spéciaux en fonction de votre emplacement. Permettez-moi de préciser que ceci ne concerne pas uniquement l'utilisation de l'API Windows, mais il existe trois autres emplacements principaux où ces chaînes interagissent avec le C++ standard. Il s'agit de littéraux de chaîne, générés en std::cout à l'aide de << et en transmettant un nom de fichier à std::fstream.

Je dirai tout à l'heure que je suis un programmeur et non un spécialiste des langues. Je reconnais que USC2 et UTF-16 ne sont pas identiques, mais pour mes besoins, ils sont suffisamment proches pour être interchangeables et je les utilise tels quels ici. Je ne suis pas sûr de savoir qui utilise Windows, mais je n'ai généralement pas besoin de savoir non plus. J'ai déclaré UCS2 dans cette réponse. Je vous prie donc de m'excuser d'avance si je contrarie qui que ce soit avec mon ignorance à ce sujet et que je serai heureux de le changer si j'ai des problèmes.

Littéraux de chaîne

Si vous entrez des littéraux de chaîne ne contenant que des caractères pouvant être représentés par votre page de codes, VS les stocke dans votre fichier avec un codage sur un octet par caractère en fonction de votre page de codes. 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 par être différent. Si vous exécutez votre code sur un ordinateur en utilisant une page de code différente, je ne suis pas sûr que le caractère change également.

Si vous entrez des chaînes de caractères qui ne peuvent pas être représentées par votre page de codes, VS vous demandera de sauvegarder le fichier au format Unicode. Le fichier sera ensuite codé au format UTF-8. Cela signifie que tous les caractères non ASCII (y compris ceux qui figurent sur votre page de codes) seront représentés par 2 octets ou plus. Cela signifie que si vous donnez votre source à quelqu'un d'autre, la source sera identique. Cependant, avant de transmettre le code source au compilateur, VS convertit le texte codé UTF-8 en texte codé de page de code et tous les caractères manquants dans la page de code sont remplacés par ?.

Le seul moyen de garantir la représentation correcte d'un littéral de chaîne Unicode dans VS consiste à faire précéder le littéral de chaîne d'un L pour en faire un littéral de chaîne large. Dans ce cas, VS convertira le texte codé UTF-8 du fichier en UCS2. Vous devez ensuite passer ce littéral de chaîne dans un constructeur std::wstring ou le convertir en utf-8 et le placer dans un std::string. Ou, si vous le souhaitez, vous pouvez utiliser les fonctions de l'API Windows pour le coder à l'aide de votre page de code afin de le placer dans un std::string, mais vous pourriez également ne pas avoir utilisé de littéral de chaîne large.

std :: cout

Lorsque vous exportez vers la console en utilisant <<, vous ne pouvez utiliser que std::string, pas std::wstring, et le texte doit être codé à l'aide de votre page de code locale. Si vous avez un std::wstring, vous devez le convertir à l'aide de l'une des fonctions de l'API Windows. Tous les caractères qui ne figurent pas sur votre page de code sont remplacés par ? (vous pouvez peut-être changer le caractère, je ne m'en souviens plus).

std :: noms de fichiers fstream

Le système d'exploitation Windows utilise UCS2/UTF-16 pour ses noms de fichiers. Ainsi, 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 contenant des caractères ne figurant pas sur votre page de codes, vous devez utiliser std::wstring. Il n'y a pas d'autre moyen. Il s’agit d’une extension spécifique à std::fstream propre à Microsoft et ne sera donc probablement pas compilée sur d’autres systèmes. Si vous utilisez std :: string, vous ne pouvez utiliser que les noms de fichiers contenant uniquement des caractères sur votre page de codes.

Vos options

Si vous travaillez uniquement sur Linux, vous n’avez probablement pas été aussi loin. Utilisez simplement UTF-8 std::string partout.

Si vous travaillez uniquement sous Windows, utilisez UCS2 std::wstring partout. Certains puristes peuvent utiliser UTF8, puis convertir si nécessaire, mais pourquoi s'embêter avec les tracas.

Si vous êtes multi-plateforme, alors c'est un gâchis d'être franc. Si vous essayez d'utiliser UTF-8 partout sur Windows, vous devez faire très attention à vos littéraux de chaîne et à leur sortie sur la console. Vous pouvez facilement corrompre vos chaînes là-bas. Si vous utilisez std::wstring partout sur Linux, vous n'avez peut-être pas accès à la version complète de std::fstream; vous devez donc effectuer la conversion, mais il n'y a aucun risque de corruption. Donc, 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 __ nom_variable__ 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.

Donc pour répondre à vos questions

1) Si vous programmez pour Windows, tout le temps, si vous utilisez plusieurs plates-formes, alors peut-être tout le temps, à moins que vous ne souhaitiez traiter d'éventuels problèmes de corruption sous Windows ou écrire du code avec la plateforme spécifique #ifdefs en utilisant Linux alors jamais.

2) oui En outre, sur Linux, vous pouvez également l'utiliser pour tous les caractères Unicode. Sous Windows, vous ne pouvez l’utiliser pour tous les codes Unicode que si vous choisissez d’encoder manuellement à l’aide de UTF-8. Mais les API Windows et les classes C++ standard s’attendent à ce que le std::string soit codé à l’aide de la page de codes de paramètres régionaux. Ceci inclut tous les caractères ASCII plus 128 autres caractères, qui changent en fonction de la page de code que votre ordinateur est configuré pour utiliser.

3) Je crois que oui, mais si ce n'est pas le cas, il ne s'agit que d'une simple typedef de 'std :: basic_string' utilisant wchar_t au lieu de unicodestring.

4) Un caractère large est un type de caractère plus grand que le type standard à 1 octet char. Sous Windows, il s'agit de 2 octets et sous Linux, de 4 octets.

4)A wide character is a character type which is bigger than the 1 byte standard char type. On Windows it is 2 bytes, on Linux it is 4 bytes.

0
Phil Rosenberg