82 votes

Ce qui est "mal" avec C++ wchar_t et wstrings? Quelles sont certaines des solutions de rechange à l'échelle de caractères?

J'ai vu beaucoup de gens dans le C++ (en particulier les ##c++ sur freenode) s'indignent de l'utilisation de wstrings et wchar_t, et leur utilisation dans l'api windows. Précisément ce qui est "mal" avec wchar_t et wstring, et si je veux soutenir l'internationalisation, quelles sont les alternatives à l'échelle de caractères?

113voto

bames53 Points 38303

Qu'est-ce que wchar_t?

wchar_t est définie de telle façon que tous les paramètres régionaux de l'encodage peut être converti à un wchar_t représentation où chaque wchar_t représente exactement une codepoint:

Type wchar_t est un type distinct dont les valeurs peuvent représenter des codes distincts pour tous les membres de la plus grande étendue de caractère spécifié parmi les paramètres régionaux pris en charge (22.3.1).

                                                                               - C++ [de base.fondamentaux] 3.9.1/5

Ce n'est pas exiger que wchar_t être suffisamment grand pour représenter tous les caractères de toutes les langues simultanément. Qui est, le codage utilisé pour les wchar_t peuvent différer entre les paramètres régionaux. Ce qui signifie que vous ne pouvez pas nécessairement convertir une chaîne de wchar_t à l'aide de l'un des paramètres régionaux et ensuite de les convertir en arrière de l'omble à l'aide d'une autre région.1

Depuis l'utilisation de wchar_t comme une représentation commune entre tous les paramètres régionaux semble être la principale utilisation d'wchar_t, dans la pratique, vous pourriez vous demander ce que c'est bon pour si pas que.

L'original de l'intention et le but de wchar_t était de faire du traitement de texte simple en le définissant telle qu'elle nécessite un one-to-one mapping à partir d'une chaîne de code-parts pour le texte des personnages, permettant ainsi l'utilisation de la même simples algorithmes sont utilisés avec des chaînes ascii de travailler avec d'autres langues.

Malheureusement, le libellé de wchar_t spécifications de supposer un one-to-one mapping entre les personnages et codepoints pour atteindre cet objectif. Unicode pauses que l'hypothèse2, de sorte que vous ne pouvez pas l'utiliser en toute sécurité wchar_t pour du texte simple des algorithmes.

Cela signifie que le logiciel portable ne peut pas utiliser wchar_t soit comme une représentation commune pour le texte entre les paramètres régionaux, ou à permettre l'utilisation de texte simple des algorithmes.

Quel est wchar_t aujourd'hui?

Pas beaucoup, pour un code portable, de toute façon. Si __STDC_ISO_10646__ est défini, les valeurs de wchar_t représentent directement Unicode codepoints avec les mêmes valeurs dans tous les lieux. Que fait-il sécuritaire de faire de l'inter-régionaux des conversions mentionné plus tôt. Cependant, vous ne pouvez pas compter uniquement sur elle de décider que vous pouvez utiliser wchar_t de cette façon parce que, bien que la plupart des plates-formes unix définir, Windows n'a pas même si Windows utilise le même wchar_t locale dans toutes les régions.

La raison pour Windows ne définit __STDC_ISO_10646__ est parce que Windows utiliser l'UTF-16 comme son wchar_t de codage, et parce que UTF-16 utilise des paires de substitution pour représenter codepoints plus grand que U+FFFF, ce qui signifie que UTF-16 n'est pas satisfait aux exigences pour l' __STDC_ISO_10646__.

Pour la plate-forme de code spécifique wchar_t peut-être plus utile. Il est essentiellement nécessaire sur Windows (par exemple, certains fichiers ne peuvent simplement pas être ouvert sans l'aide de wchar_t les noms de fichiers), si Windows est la seule plate-forme où cela est vrai pour autant que je sais (donc peut-être que nous pouvons penser de wchar_t comme "Windows_char_t').

Avec le recul, wchar_t est clairement pas utile pour simplifier le traitement de texte, ou comme stockage pour les paramètres régionaux de texte indépendant. Code Portable ne devrait pas tenter de l'utiliser à ces fins. Du code Non portable peut être utile tout simplement parce que certaines API exige.

Alternatives

L'alternative est d'utiliser UTF-8 C les cordes, même sur les plates-formes pas particulièrement sympathique vers UTF-8.

De cette façon, on peut écrire du code portable à l'aide d'une représentation de texte sur les plates-formes, utiliser des types de données pour leur usage prévu, obtenir de la langue de support pour ces types (par exemple, les littéraux de chaîne, même si certains trucs sont nécessaires pour le faire fonctionner pour certains compilateurs), certains de la bibliothèque standard support, débogueur (plus d'un tour peut être nécessaire), etc. Avec des caractères larges, il est généralement difficile, voire impossible d'obtenir tout cela, et vous pouvez obtenir des pièces différentes sur différentes plates-formes.

Une chose UTF-8 n'offrent pas la possibilité d'utiliser de texte simple des algorithmes tels que sont possible avec l'ASCII. Dans ce UTF-8 n'est pas pire que n'importe quel autre codage Unicode. En fait, il peut être considéré comme meilleur, parce que multi-unité de code représentations en UTF-8 sont plus fréquentes et donc des bugs dans le code de la manipulation de tels largeur variable des représentations de personnages sont plus susceptibles d'être remarqué et corrigé que si vous essayez de coller à l'UTF-32 avec NFC ou NFKC.

De nombreuses plates-formes d'utiliser l'UTF-8 comme leur patrie encodage et de nombreux programmes ne nécessitent pas d'importantes du traitement de texte, et donc l'écriture d'un programme internationalisé sur ces plates-formes est un peu différent de l'écriture de code sans tenir compte de l'internationalisation. L'écriture, plus largement, du code portable, ou d'écrire sur d'autres plates-formes nécessite l'insertion des conversions les limites de l'Api qui utilisent d'autres encodages.

Une autre alternative utilisée par certains logiciels est de choisir une croix-plate-forme de représentation, tels que unsigned short tableaux de la tenue de l'UTF-16 données, puis de fournir tout le support de bibliothèque et tout simplement de vivre avec les coûts de support de la langue, etc.

C++11 ajoute de nouveaux types de caractères larges comme des alternatives à wchar_t, char16_t et char32_t avec la langue du standard/les fonctionnalités de la bibliothèque. Ce ne sont pas effectivement garanti pour être en UTF-16 et UTF-32, mais je n'imagine pas majeur de la mise en œuvre permettra d'utiliser quoi que ce soit d'autre. C++11 améliore également le support UTF-8, par exemple avec l'encodage UTF-8 littéraux de chaîne de sorte qu'il ne sera pas nécessaire de tromper VC++ dans la production de l'UTF-8 cordes (bien que je puisse continuer à le faire plutôt que d'utiliser l' u8 préfixe).

Solutions de rechange pour éviter

TCHAR: TCHAR est pour la migration des anciens programmes Windows en assumer l'héritage des codages de char à wchar_t, et il est préférable d'oublier, sauf si votre programme a été écrit dans certains millénaire précédent. Ce n'est pas portable et est intrinsèquement imprécis à propos de son encodage et même son type de données, le rendant inutilisable avec n'importe quel non-TCHAR en fonction de l'API. Puisque son but est de migration de wchar_t, qui nous l'avons vu ci-dessus n'est pas une bonne idée, il n'y a pas de valeur, que ce soit dans l'utilisation de TCHAR.


1. Les caractères qui sont représentables dans wchar_t cordes, mais qui ne sont pas pris en charge dans les paramètres régionaux ne sont pas tenues d'être représentées avec une seule wchar_t valeur. Cela signifie que wchar_t pourrait utiliser une largeur variable de codage de certains caractères, une autre violation claire de l'intention de wchar_t. Même si on peut soutenir qu'un caractère soit représentable par wchar_t est assez dire que les paramètres régionaux "prend en charge" de ce personnage, auquel cas la variable de la largeur des codages ne sont pas légales et de la Fenêtre de l'utilisation de l'UTF-16 est non-conforme.

2. Unicode permet à de nombreux personnages de être représentée, avec de multiples points de code, qui crée les mêmes problèmes pour du texte simple, les algorithmes de largeur variable encodages. Même si l'on maintient strictement composé de normalisation, certains personnages encore besoin de plusieurs points de code. Voir: http://www.unicode.org/standard/where/

19voto

paulsm4 Points 39422

Il n'y a rien de "mal" avec wchar_t. Le problème est que, de retour en NT 3.les x jours, Microsoft a décidé que l'Unicode est Bon (il est), et à mettre en œuvre Unicode 16 bits, wchar_t caractères. Ainsi, la plupart de Microsoft littérature à partir du milieu des années 90 assez bien assimilé Unicode == utf16 == wchar_t.

Qui, malheureusement, n'est pas du tout le cas. "Caractères larges" sont pas nécessairement de 2 octets, sur toutes les plates-formes, dans toutes les circonstances.

C'est l'une des meilleures amorces sur "Unicode" (indépendamment de cette question, indépendante de C++) j'ai jamais vu: j'ai très recommandons:

Et je crois sincèrement que la meilleure façon de traiter avec "8-bit ASCII" vs "Win32 caractères larges" vs "wchar_t en général", est tout simplement d'accepter que "Windows est Différent" ... et le code en conséquence.

À mon humble avis...

PS:

Je suis totalement d'accord avec jamesdlin ci-dessus:

Sur Windows, vous n'avez pas vraiment le choix. Son interne de l'Api ont été conçu pour UCS-2, ce qui est raisonnable à l'époque puisque c'était avant de la longueur de la variable UTF-8 et UTF-16 codages ont été normalisé. Mais maintenant qu'ils sont en faveur de l'UTF-16, ils se sont retrouvés avec le pire des deux mondes.

-3voto

paulsm4 Points 39422

Lecture obligatoire:

The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

Si vous programmez en Java ou en .Net (VB.Net ou C#) - c'est en grande partie un non-problème: les deux sont en Unicode par défaut. Si vous programmez dans le "classique" de l'API Win32), votre meilleur pari est probablement d'utiliser TCHAR et _T() macros (plutôt qu'explicitement l'utilisation wchar).

Tous les compilateurs Microsoft VS2005 et plus tard, je crois, par défaut de 16 bits pour le C/C++ de toute façon (une partie de la raison pour laquelle je encore utiliser MSVS 6.0 dès que je peux ;)).

Une autre bonne (bien qu'un peu datée du lien):

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X