TCHAR est-il toujours pertinent?

87

Je suis nouveau dans la programmation Windows et après avoir lu le livre Petzold, je me demande:

est-ce toujours une bonne pratique d'utiliser le TCHARtype et la _T()fonction pour déclarer des chaînes ou si je devrais simplement utiliser les chaînes wchar_tet L""dans le nouveau code?

Je ciblerai uniquement Windows 2000 et plus et mon code sera i18n dès le démarrage.

Fábio
la source

Réponses:

15

J'utiliserais toujours la syntaxe TCHAR si je faisais un nouveau projet aujourd'hui. Il n'y a pas beaucoup de différence pratique entre son utilisation et la syntaxe WCHAR, et je préfère le code qui est explicite dans le type de caractère. Étant donné que la plupart des fonctions API et des objets d'assistance prennent / utilisent des types TCHAR (par exemple: CString), il est logique de l'utiliser. De plus, cela vous donne de la flexibilité si vous décidez d'utiliser le code dans une application ASCII à un moment donné, ou si Windows évolue un jour vers Unicode32, etc.

Si vous décidez d'emprunter la voie WCHAR, je serais explicite à ce sujet. Autrement dit, utilisez CStringW au lieu de CString et transtypez des macros lors de la conversion en TCHAR (par exemple: CW2CT).

C'est mon avis, de toute façon.

pseudo
la source
En effet, c'est ce qui fonctionnera encore lorsque le codage des caractères sera finalement modifié «à nouveau».
Medinoc
11
Vous préférez le code qui est explicite dans ce qu'est le type de caractère, et utilisez donc un type qui est parfois ceci et parfois cela? Très convaincant.
Deduplicator
4
−1 pour l'incohérence notée par @Deduplicator, et pour le conseil de gain négatif d'utiliser une macro qui peut être n'importe quelle (et ne sera généralement pas testée pour plus d'une valeur spécifique).
Acclamations et hth. - Alf
90

La réponse courte: NON .

Comme tous les autres déjà écrits, de nombreux programmeurs utilisent encore les TCHAR et les fonctions correspondantes. À mon humble avis, tout le concept était une mauvaise idée . Le traitement des chaînes UTF-16 est très différent du simple traitement des chaînes ASCII / MBCS. Si vous utilisez les mêmes algorithmes / fonctions avec les deux (c'est sur quoi est basée l'idée TCHAR!), Vous obtenez de très mauvaises performances sur la version UTF-16 si vous faites un peu plus que la simple concaténation de chaînes (comme analyse, etc.). La principale raison sont les substituts .

À la seule exception où vous devez vraiment compiler votre application pour un système qui ne prend pas en charge Unicode, je ne vois aucune raison d'utiliser ce bagage du passé dans une nouvelle application.

Sascha
la source
6
Fait amusant: UTF-16 n'était pas toujours présent sur la plate-forme NT. Des points de code de substitution ont été introduits avec Unicode 2.0, en 1996, année de la sortie de NT 4. Jusqu'à, IIRC, (y compris) Windows 2000, toutes les versions NT utilisaient UCS-2, en fait un sous-ensemble de UTF-16 qui supposait que chaque caractère était représentable avec un point de code (c'est-à-dire sans substitut).
0xC0000022L
3
btw, même si je suis d'accord que cela TCHARne devrait plus être utilisé, je ne suis pas d'accord pour dire que c'était une mauvaise idée. Je pense aussi que si vous choisissez d'être explicite au lieu d'utiliser, TCHARvous devez être explicite partout . Ie n'utilise pas non plus de fonctions avec TCHAR/ _TCHAR(comme _tmain) dans leur déclaration. En termes simples: soyez cohérent. +1, toujours.
0xC0000022L
3
C'était une bonne idée lors de son introduction, mais cela ne devrait pas être pertinent dans le nouveau code.
Adrian McCarthy
4
Vous déformez, ce qui a TCHARété initialement introduit pour: Pour faciliter le développement du code pour les versions Windows 9x et Windows NT de Windows. À ce moment-là, l'implémentation UTF-16 de Windows NT était UCS-2 et les algorithmes d'analyse / manipulation de chaînes étaient identiques. Il n'y avait pas de substituts. Et même avec des substituts, les algorithmes pour DBCS (le seul encodage MBCS pris en charge pour Windows) et UTF-16 sont les mêmes: dans les deux encodages, un point de code se compose d'une ou deux unités de code.
IInspectable
Supposons que je veuille utiliser FormatMessage () pour convertir une valeur de WSAGetLastError () en quelque chose d'imprimable. La documentation de WSAGetLastError () indique qu'elle prend LPTSTR comme pointeur vers le tampon. Je n'ai vraiment pas d'autre choix que d'utiliser TCHAR, non?
Edward Falk
80

Je suis d'accord avec Sascha. La prémisse sous-jacente de TCHAR/ _T()/ etc. est que vous pouvez écrire une application basée sur "ANSI" puis lui donner comme par magie le support Unicode en définissant une macro. Mais cela repose sur plusieurs mauvaises hypothèses:

Que vous construisez activement les versions MBCS et Unicode de votre logiciel

Sinon, vous allez glisser et utiliser ordinaires char*cordes dans de nombreux endroits.

Que vous n'utilisez pas d'échappements anti-slash non ASCII dans les littéraux _T ("...")

À moins que votre encodage "ANSI" ne soit ISO-8859-1, les littéraux char*et les résultats wchar_t*ne représenteront pas les mêmes caractères.

Les chaînes UTF-16 sont utilisées comme les chaînes "ANSI"

Ils ne sont pas. Unicode introduit plusieurs concepts qui n'existent pas dans la plupart des encodages de caractères hérités. Substituts. Combinaison de caractères. Normalisation. Règles de casse conditionnelles et sensibles à la langue.

Et peut-être plus important encore, le fait que l'UTF-16 est rarement enregistré sur disque ou envoyé sur Internet: UTF-8 a tendance à être préféré pour la représentation externe.

Que votre application n'utilise pas Internet

(Maintenant, cela peut être une hypothèse valable pour votre logiciel, mais ...)

Le Web fonctionne sur UTF-8 et une pléthore d'encodages plus rares . Le TCHARconcept n'en reconnaît que deux: "ANSI" (qui ne peut pas être UTF-8 ) et "Unicode" (UTF-16). Cela peut être utile pour rendre vos appels d'API Windows compatibles Unicode, mais c'est sacrément inutile pour rendre vos applications Web et de messagerie compatibles Unicode.

Que vous n'utilisez aucune bibliothèque non-Microsoft

Personne d'autre n'utilise TCHAR. Poco utilise std::stringet UTF-8. SQLite a des versions UTF-8 et UTF-16 de son API, mais non TCHAR. TCHARn'est même pas dans la bibliothèque standard, donc non, std::tcoutsauf si vous voulez le définir vous-même.

Ce que je recommande à la place de TCHAR

Oubliez que les encodages "ANSI" existent, sauf lorsque vous avez besoin de lire un fichier qui n'est pas valide UTF-8. Oubliez TCHARaussi. Appelez toujours la version "W" des fonctions de l'API Windows. #define _UNICODEjuste pour vous assurer de ne pas appeler accidentellement une fonction «A».

Utilisez toujours les encodages UTF pour les chaînes: UTF-8 pour les charchaînes et UTF-16 (sous Windows) ou UTF-32 (sur les systèmes de type Unix) pour les wchar_tchaînes. typedef UTF16et les UTF32types de caractères pour éviter les différences de plate-forme.

dan04
la source
6
Appel de 2012: il y a encore des applications à maintenir sans #define _UNICODEmême maintenant. Fin de la transmission :)
0xC0000022L
12
@ 0xC0000022L la question portait sur le nouveau code. Lorsque vous maintenez un ancien code, vous devez évidemment travailler avec l'environnement pour lequel le code est écrit. Si vous maintenez une application COBOL, peu importe si COBOL est un bon langage ou non, vous êtes coincé avec lui. Et si vous gérez une application qui repose sur TCHAR, peu importe que ce soit une bonne décision ou non, vous êtes coincé avec elle.
jalf
2
En effet, TCHAR n'est utile que dans COBOL)
Pavel Radzivilovsky
1
_UNICODEcontrôle la façon dont les mappages de texte générique sont résolus dans le CRT. Si vous ne souhaitez pas appeler la version ANSI d'une API Windows, vous devez définir UNICODE.
IInspectable le
18

Si vous vous demandez si c'est encore en pratique, alors oui - c'est encore un peu utilisé. Personne ne regardera votre code de manière amusante s'il utilise TCHAR et _T (""). Le projet sur lequel je travaille actuellement consiste à convertir ANSI en Unicode - et nous allons sur la route portable (TCHAR).

Pourtant...

Mon vote serait d'oublier toutes les macros portables ANSI / UNICODE (TCHAR, _T (""), et tous les appels _tXXXXXX, etc ...) et de supposer juste unicode partout. Je ne vois vraiment pas l'intérêt d'être portable si vous n'avez jamais besoin d'une version ANSI. J'utiliserais directement toutes les fonctions et types de caractères larges. Faites précéder tous les littéraux de chaîne d'un L.

Aardvark
la source
3
Vous pourriez écrire du code que vous voudrez utiliser ailleurs où vous avez besoin d'une version ANSI, ou (comme Nick l'a dit) Windows pourrait passer à DCHAR ou autre, donc je pense toujours que c'est une très bonne idée d'utiliser TCHAR au lieu de WCHAR.
arke
Je doute que Windows passe un jour à l'UTF-32.
dan04
7
-1 pour la recommandation UTF-16. Non seulement cela crée du code non portable (centré sur Windows), ce qui est inacceptable pour les bibliothèques - même s'il peut être utilisé pour les cas les plus simples comme le code d'interface utilisateur - il n'est pas efficace même sur Windows lui-même. utf8everywhere.org
Pavel Radzivilovsky
11

L'article Introduction à la programmation Windows sur MSDN dit

Les nouvelles applications doivent toujours appeler les versions Unicode (de l'API).

Les macros TEXT et TCHAR sont moins utiles aujourd'hui, car toutes les applications doivent utiliser Unicode.

Je m'en tiendrai à wchar_tet L"".

Steven
la source
4
Steven, vous citez un texte écrit par quelqu'un qui ne comprend pas le sens du mot «Unicode». C'est l'un de ces documents malheureux de l'époque de la confusion UCS-2.
Pavel Radzivilovsky
2
@PavelRadzivilovsky: Le document a été écrit pour un système, où Unicode et UTF-16LE sont couramment utilisés de manière interchangeable. Bien que techniquement inexact, il n'en est pas moins sans ambiguïté. Ceci est également explicitement souligné dans l'introduction du même texte: "Windows représente les caractères Unicode en utilisant le codage UTF-16 [...]" .
IInspectable
11

Je voudrais suggérer une approche différente (aucune des deux).

Pour résumer, utilisez char * et std :: string, en supposant le codage UTF-8, et effectuez les conversions en UTF-16 uniquement lors de l'encapsulation des fonctions API.

Vous trouverez plus d'informations et une justification de cette approche dans les programmes Windows sur http://www.utf8everywhere.org .

Pavel Radzivilovsky
la source
@PavelRadzivilovsky, lors de l'implémentation de votre suggestion dans une application VC ++, définirions-nous le jeu de caractères VC ++ sur «Aucun» ou «Multibyte (MBCS)»? La raison pour laquelle je demande est que je viens d'installer Boost :: Locale et que le jeu de caractères par défaut était MBCS. FWIW, mon application ASCII pure a été définie sur «Aucun» et je l'ai maintenant définie sur «MBCS» (puisque j'utiliserai Boost :: Locale) et cela fonctionne très bien. S'il vous plaît donnez votre avis.
Caroline Beltran
Comme le recommande utf8everywhere, je le définirais sur «Utiliser le jeu de caractères Unicode». Cela annonce une sécurité supplémentaire, mais n'est pas obligatoire. L'auteur de Boost :: locale est un gars très intelligent, je suis sûr qu'il a fait la bonne chose.
Pavel Radzivilovsky
1
Le mantra UTF-8 Everywhere ne deviendra pas la bonne solution, simplement parce qu'il est répété plus souvent. UTF-8 est sans aucun doute un encodage attrayant pour la sérialisation (par exemple, des fichiers ou des sockets réseau), mais sous Windows, il est souvent plus approprié de stocker des données de caractères en utilisant l'encodage UTF-16 natif en interne et de les convertir à la limite de l'application. L'une des raisons est que UTF-16 est le seul encodage, qui peut être converti immédiatement en tout autre encodage pris en charge. Ce n'est pas le cas avec UTF-8.
IInspectable
"..UTF-16 est le seul encodage, qui peut être converti immédiatement en tout autre encodage pris en charge." Que voulez-vous dire? Quel est le problème pour convertir l'encodage UTF-8 en autre chose?
Pavel Radzivilovsky
1
Je ne comprends pas. À autre chose - comme quoi? Par exemple UCS-4? Pourquoi pas? Semble très facile, tout algorithme numérique.
Pavel Radzivilovsky
7

TCHAR/ WCHARpourrait suffire pour certains projets hérités. Mais pour les nouvelles applications, je dirais NON .

Tous ces TCHAR/ WCHARtrucs sont là pour des raisons historiques. TCHARfournit une manière élégante (déguisement) de basculer entre le codage de texte ANSI (MBCS) et le codage de texte Unicode (UTF-16). Dans le passé, les gens ne comprenaient pas le nombre de caractères de toutes les langues du monde. Ils ont supposé que 2 octets étaient suffisants pour représenter tous les caractères et ainsi avoir un schéma de codage de caractères de longueur fixe utilisant WCHAR. Cependant, ce n'est plus le cas après la sortie d'Unicode 2.0 en 1996 .

Autrement dit: peu importe ce que vous utilisez dans CHAR/ WCHAR/ TCHAR, la partie de traitement de texte de votre programme devrait être capable de gérer des caractères de longueur variable pour l'internationalisation.

Vous devez donc en fait faire plus que d'en choisir un dans CHAR/ WCHAR/ TCHARpour la programmation sous Windows:

  1. Si votre application est petite et n'implique pas de traitement de texte (c'est-à-dire simplement en passant autour de la chaîne de texte comme arguments), alors tenez-vous-en WCHAR. Comme il est plus simple de travailler avec WinAPI avec le support Unicode.
  2. Sinon, je suggérerais d'utiliser UTF-8 comme encodage interne et de stocker les textes dans des chaînes de caractères ou std :: string. Et convertissez-les en UTF-16 lorsque vous appelez WinAPI. UTF-8 est maintenant l'encodage dominant et il existe de nombreuses bibliothèques et outils pratiques pour traiter les chaînes UTF-8.

Consultez ce merveilleux site Web pour une lecture plus approfondie: http://utf8everywhere.org/

Léopard
la source
2
"UTF-8 est maintenant l'encodage dominant" - Cela a mal tourné, en omettant la deuxième partie de la citation ( "pour le World Wide Web" ). Pour les applications de bureau, le codage de caractères natif le plus utilisé est probablement encore UTF-16. Windows l'utilise, Mac OS X aussi, tout comme les types de chaînes .NET et Java. Cela représente une quantité énorme de code là-bas. Ne vous méprenez pas, il n'y a rien de mal avec UTF-8 pour la sérialisation. Mais le plus souvent (en particulier sous Windows), vous constaterez que l'utilisation de l'UTF-16 en interne est plus appropriée.
IInspectable
4

Oui absolument; au moins pour la macro _T. Je ne suis pas si sûr des trucs à gros caractères, cependant.

La raison en est de mieux prendre en charge WinCE ou d'autres plates-formes Windows non standard. Si vous êtes sûr à 100% que votre code restera sur NT, vous pouvez probablement simplement utiliser des déclarations C-string régulières. Cependant, il est préférable de tendre vers une approche plus flexible, car il est beaucoup plus facile de #définir cette macro sur une plate-forme non Windows par rapport à parcourir des milliers de lignes de code et à l'ajouter partout au cas où vous auriez besoin de porter une bibliothèque. à Windows Mobile.

Nik Reiman
la source
1
WinCE utilise des chaînes wchar_t 16 bits comme Win32. Nous avons une grande base de code qui fonctionne sur WinCE et Win32 et nous n'utilisons jamais TCHAR.
mhenry1384
2

À mon humble avis, s'il y a des TCHAR dans votre code, vous travaillez au mauvais niveau d'abstraction.

Utilisez tout type de chaîne est plus pratique pour vous lorsqu'il s'agit de traitement de texte - ce sera , espérons - être quelque chose unicode soutenir, mais c'est à vous. Effectuez la conversion aux limites de l'API du système d'exploitation si nécessaire.

Lorsque vous traitez des chemins de fichiers, créez votre propre type personnalisé au lieu d'utiliser des chaînes. Cela vous permettra des séparateurs de chemins indépendants du système d'exploitation, vous donnera une interface plus facile à coder que la concaténation et le fractionnement manuels de chaînes, et sera beaucoup plus facile à adapter à différents systèmes d'exploitation (ansi, ucs-2, utf-8, peu importe) .

snemarch
la source
Unicode a au moins trois encodages actuels (UTF-8, UTF-16, UTF-32) et un encodage obsolète (UCS-2, un sous-ensemble de ce qui est maintenant UTF-16). À laquelle parlez-vous? J'aime le reste des suggestions cependant +1
0xC0000022L
2

Les seules raisons que je vois pour utiliser autre chose que le WCHAR explicite sont la portabilité et l'efficacité.

Si vous voulez rendre votre exécutable final aussi petit que possible, utilisez char.

Si vous ne vous souciez pas de l'utilisation de la RAM et que vous voulez que l'internationalisation soit aussi simple qu'une simple traduction, utilisez WCHAR.

Si vous souhaitez rendre votre code flexible, utilisez TCHAR.

Si vous prévoyez d'utiliser uniquement les caractères latins, vous pouvez également utiliser les chaînes ASCII / MBCS pour que votre utilisateur n'ait pas besoin d'autant de RAM.

Pour les personnes qui sont "i18n dès le départ", économisez vous-même l'espace de code source et utilisez simplement toutes les fonctions Unicode.

Trololol
la source
-1

Juste ajouter à une vieille question:

NON

Allez démarrer un nouveau projet CLR C ++ dans VS2010. Microsoft eux-mêmes utilisent L"Hello World"», a déclaré Nuff.

kizzx2
la source
13
Le CLR est un environnement très différent du code non managé. Ce n’est pas un argument.
Cody Gray
3
Même Microsoft fait des erreurs.
Pavel Radzivilovsky
6
-1 La question est étiquetée Cet C++. Les réponses peuvent toujours être supprimées par leurs auteurs respectifs. Ce serait le bon moment pour utiliser cette disposition.
IInspectable
-1

TCHARont une nouvelle signification pour porter de WCHARà CHAR.

https://docs.microsoft.com/en-us/windows/uwp/design/globalizing/use-utf8-code-page

Les versions récentes de Windows 10 ont utilisé la page de codes ANSI et les API -A comme moyen d'introduire la prise en charge UTF-8 dans les applications. Si la page de codes ANSI est configurée pour UTF-8, les API -A fonctionnent en UTF-8.

PosséderIsMagique
la source