Pré-requis : http://www.joelonsoftware.com/articles/Unicode.html
L'article ci-dessus est une lecture indispensable qui explique ce qu'est l'unicode mais quelques questions subsistent. Oui, l'UNICODE a un point de code unique pour chaque caractère dans chaque langue et, en outre, ils peuvent être codés et stockés en mémoire potentiellement différemment de ce que le code réel est. De cette façon, nous pouvons économiser de la mémoire en utilisant par exemple l'encodage UTF-8, ce qui est très bien si la langue supportée est seulement l'anglais et que la représentation en mémoire est essentiellement la même que celle de l'ASCII - ceci bien sûr en connaissant l'encodage lui-même. En théorie, si nous connaissons le codage, nous pouvons stocker ces caractères UNICODE plus longs comme bon nous semble et les relire. Mais le monde réel est un peu différent.
Comment stocker un caractère/chaîne UNICODE dans un programme C++ ? Quel encodage utilisez-vous ? La réponse est que vous n'utilisez pas d'encodage mais que vous stockez directement les points de code UNICODE dans une chaîne de caractères unicode, tout comme vous stockez les caractères ASCII dans une chaîne ASCII. La question est de savoir quelle taille de caractère vous devez utiliser puisque les caractères UNICODE n'ont pas de taille fixe. La réponse est simple : vous choisissez le corps de caractère qui est suffisamment large pour contenir le point de code de caractère le plus élevé (langue) que vous souhaitez prendre en charge.
La théorie selon laquelle un caractère UNICODE peut prendre 2 octets ou plus est toujours valable et cela peut créer une certaine confusion. Ne devrions-nous pas stocker les points de code dans 3 ou 4 octets, ce qui représente réellement tous les caractères unicode ? Pourquoi Visual C++ stocke-t-il l'unicode dans wchar_t, qui n'occupe que 2 octets, ce qui est clairement insuffisant pour stocker tous les points de code UNICODE ?
La raison pour laquelle nous stockons le point de code du caractère UNICODE sur 2 octets dans Visual C++ est en fait exactement la même raison pour laquelle nous stockions le caractère ASCII (=anglais) sur un octet. À l'époque, nous ne pensions qu'à l'anglais et un seul octet était suffisant. Aujourd'hui, nous pensons à la plupart des langues internationales, mais pas à toutes, et nous utilisons donc deux octets, ce qui est suffisant. Il est vrai que cette représentation ne nous permettra pas de représenter les points de code qui nécessitent 3 octets ou plus, mais nous ne nous en soucions pas encore, car ces personnes n'ont même pas encore acheté d'ordinateur. Oui, nous n'utilisons pas 3 ou 4 octets parce que nous sommes toujours avares de mémoire, pourquoi stocker l'octet supplémentaire 0 (zéro) avec chaque caractère si nous ne l'utilisons jamais (ce langage). Encore une fois, c'est exactement pour les mêmes raisons que l'ASCII stockait chaque caractère dans un octet, pourquoi stocker un caractère dans 2 octets ou plus lorsque l'anglais peut être représenté dans un octet et qu'il reste de la place pour ces caractères spéciaux supplémentaires !
En théorie, deux octets ne suffisent pas à présenter tous les points de code Unicode, mais ils sont suffisants pour contenir tout ce qui peut nous intéresser pour l'instant. Une véritable représentation de chaîne UNICODE pourrait stocker chaque caractère sur 4 octets, mais ces langues ne nous intéressent pas.
Imaginez que dans 1000 ans, nous trouvions des extraterrestres amicaux et en abondance et que nous voulions communiquer avec eux en incorporant leurs innombrables langues. La taille d'un seul caractère unicode augmentera encore, peut-être jusqu'à 8 octets, afin de prendre en compte tous leurs points de code. Cela ne signifie pas que nous devrions commencer à utiliser 8 octets pour chaque caractère unicode dès maintenant. La mémoire est une ressource limitée, nous allouons ce dont nous avons besoin.
Puis-je traiter une chaîne UNICODE comme une chaîne de style C ?
Une chaîne ASCII peut encore être manipulée en C++ et c'est assez courant en la saisissant par son pointeur char * où les fonctions C peuvent être appliquées. Cependant, l'application des fonctions C actuelles sur une chaîne UNICODE n'aura aucun sens car elle peut contenir un seul octet NULL qui met fin à une chaîne C.
Une chaîne de caractères UNICODE n'est plus un simple tampon de texte, c'est vrai mais c'est maintenant plus compliqué qu'un flux de caractères d'un seul octet se terminant par un octet NULL. Ce tampon peut être géré par son pointeur, même en C, mais il faudra un appel compatible UNICODE ou une bibliothèque C qui pourra lire et écrire ces chaînes et effectuer des opérations.
Cela est facilité en C++ par une classe spécialisée qui représente une chaîne UNICODE. Cette classe gère la complexité du tampon de la chaîne unicode et fournit une interface facile. Cette classe décide également si chaque caractère de la chaîne unicode est de 2 octets ou plus - ce sont des détails d'implémentation. Aujourd'hui, elle peut utiliser wchar_t (2 octets) mais demain, elle pourra utiliser 4 octets pour chaque caractère afin de prendre en charge un plus grand nombre de langues (moins connues). C'est pourquoi il est toujours préférable d'utiliser TCHAR plutôt qu'une taille fixe qui correspond à la bonne taille lorsque la mise en œuvre change.
Comment indexer une chaîne UNICODE ?
Il est également intéressant de noter, en particulier dans la gestion des chaînes de caractères en C, qu'ils utilisent l'index pour parcourir ou trouver une sous-chaîne dans une chaîne de caractères. Cet indice dans une chaîne ASCII correspond directement à la position de l'élément dans cette chaîne, mais il n'a aucune signification dans une chaîne UNICODE et doit être évité.
Que devient l'octet NULL de fin de chaîne ?
Les chaînes UNICODE sont-elles toujours terminées par l'octet NULL ? Un seul octet NULL suffit-il pour terminer la chaîne ? C'est une question d'implémentation mais un octet NULL est toujours un point de code Unicode et comme tous les autres points de code, il doit avoir la même taille que tous les autres (spécialement en l'absence d'encodage). Ainsi, le caractère NULL doit également être de deux octets si l'implémentation de la chaîne unicode est basée sur wchar_t. Tous les points de code UNICODE seront représentés par la même taille, qu'il s'agisse d'un octet nul ou d'un autre.
Est-ce que Visual C++ Debugger affiche du texte UNICODE ?
Oui, si le tampon de texte est de type LPWSTR ou de tout autre type prenant en charge UNICODE, Visual Studio 2005 et les versions ultérieures prennent en charge l'affichage du texte international dans la fenêtre de surveillance du débogueur (à condition que les polices et les packs de langue soient installés, bien sûr).
Résumé :
Le C++ n'utilise pas d'encodage pour stocker les caractères unicode mais il stocke directement les points de code UNICODE pour chaque caractère dans une chaîne. Il doit choisir une taille de caractère suffisamment grande pour contenir le plus grand caractère des langues souhaitées (au sens large) et cette taille de caractère sera fixée et utilisée pour tous les caractères de la chaîne.
Actuellement, 2 octets sont suffisants pour représenter la plupart des langues qui nous intéressent, c'est pourquoi 2 octets sont utilisés pour représenter le point de code. À l'avenir, si une nouvelle colonie spatiale amie est découverte et que nous voulons communiquer avec elle, nous devrons attribuer de nouveaux points de code Unicode à sa langue et utiliser une taille de caractères plus grande pour stocker ces chaînes.