Comment représenter des chaînes dans une application C ++ multi-plateforme (Windows, iOS, Android)?

Je développe une application dont la base de code serait multi-plateforme pour Windows, iOS et Android.

Ma question est la suivante: comment représenter en interne les chaînes utilisées par cette application pour pouvoir les utiliser efficacement sur les trois plates-formes?

Il est important de noter que j’utilise fortement DirectWrite sous Windows, dont les fonctions de l’API attendent généralement que wchar_t * soit transmis (btw. La documentation de l’API indique que “Un pointeur vers un tableau de caractères Unicode”). savoir si cela signifie qu’ils sont en codage UTF-16 ou non)

Je vois trois approches différentes (cependant, je trouve assez difficile de comprendre les détails du traitement des chaînes Unicode avec C ++ de manière multi-plateforme, alors peut-être que je manque un concept important):

  • utilisez std :: ssortingng en interne partout (et stockez les chaînes au format UTF-8?), et convertissez-les en wchar_t * si nécessaire pour l’API DirectWrite (je ne sais pas ce dont ont besoin les API de traitement de texte de Android et iOS pour le moment).
  • utilisez std :: wssortingng en interne partout. Si je comprends bien, cela ne serait pas efficace du sharepoint vue de l’utilisation de la mémoire, car wchar_t a 4 octets sur iOS et Android (cela signifie-t-il que je devrais stocker la chaîne dans UTF-16 sous Windows, et dans UTF-32 sur Android / iOS?)
  • créer une abstraction pour les chaînes avec une classe de base abstraite et implémenter un stockage interne spécifique pour les différentes plates-formes.

Quelle serait la meilleure solution? Et au fait, y a-t-il des bibliothèques multi-plateformes existantes qui résument la gestion des chaînes? (et aussi, lecture et sérialisation des chaînes Unicode)

(UPDATE: suppression de la partie avec la question sur la différence entre char * et std :: ssortingng.)

Une partie de ma question vient de mon incompréhension, ou de ma compréhension de la façon dont les classes ssortingng et wssortingng fonctionnent en C ++ (je viens de C background). Les différences entre les deux et les avantages et inconvénients ont été décrits dans cette excellente réponse: std :: wssortingng VS std :: ssortingng .

Comment fonctionne la chaîne et la chaîne

Pour moi, la découverte la plus importante à propos des chaînes de caractères et des classes de chaînes de caractères était qu’elles ne représentaient pas sémantiquement un texte codé , mais simplement une “chaîne” de char ou de wchar_t. Ils ressemblent plus à un tableau de données simple avec certaines opérations spécifiques à une chaîne (comme append et substr) plutôt qu’à un texte. Ni l’un ni l’autre n’est au courant d’aucun type d’encodage de chaîne, ils traitent chaque élément char ou wchar_t individuellement en tant que caractère distinct.

Encodages

Cependant, sur la plupart des systèmes, si vous créez une chaîne à partir d’un littéral de chaîne avec un caractère spécial comme celui-ci:

std::ssortingng s("ű"); 

Le caractère ű sera représenté par plus d’un octet en mémoire, mais cela n’a rien à voir avec la classe std :: ssortingng , qui est une fonctionnalité du compilateur car il peut encoder des littéraux de chaîne avec UTF8 (pas tous les compilateurs). (Et les littéraux de chaînes préfixés par L seront représentés par wchar_t-s dans UTF16 ou UTF32 ou autre chose, selon le compilateur).
Ainsi, la chaîne “ű” sera représentée en mémoire avec deux octets: 0xC5 0xB1 , et la classe std :: ssortingng ne saura pas que ces deux octets signifient sémantiquement un caractère (un sharepoint code Unicode) dans UTF8, d’où l’exemple de code :

 std::ssortingng s("ű"); std::cout << s.length() << std::endl; std::cout << s.substr(0, 1); 

produit le résultat suivant (selon le compilateur, certains compilateurs ne prennent pas les littéraux de chaîne comme UTF8, et certains compilateurs dépendent de l'encodage du fichier source):

 2   

La fonction size () renvoie 2, car la seule chose que sait std :: ssortingng est qu'elle stocke deux octets (deux caractères). Et substr fonctionne aussi "primitivement", il retourne une chaîne contenant le seul caractère 0xC5 , qui est affiché comme , car ce n'est pas un caractère UTF8 valide (mais cela ne dérange pas la chaîne std ::).

Et à partir de cela, nous pouvons voir que ceux qui gèrent les encodages sont les différentes API de traitement de texte de la plate-forme, comme le simple cout ou DirectWrite .

Mon approche

Dans mon application, DirectWrite est très important, car il accepte uniquement les chaînes encodées en UTF16 (sous la forme de pointeurs wchar_t *). J'ai donc décidé de stocker les chaînes à la fois en mémoire et dans un fichier encodé en UTF16. Cependant, je souhaitais une implémentation multi-plateforme capable de gérer les chaînes UTF16 sous Windows, Android et iOS, ce qui n'est pas possible avec std :: wssortingng , car sa taille (et l'encodage qu'il utilise) dépend de la plate-forme.

Pour créer une classe de chaîne multi-plateforme, ssortingctement UTF16, j'ai basé la méthode basic_ssortingng sur un type de données de 2 octets de long . Assez étonnamment - du moins pour moi - je n'ai trouvé presque aucune information à ce sujet en ligne, j'ai basé ma solution sur cette approche. Voici le code:

 // Define this on every platform to be 16 bytes! typedef unsigned short char16; struct char16_traits { typedef char16 _E; typedef _E char_type; typedef int int_type; typedef std::streampos pos_type; typedef std::streamoff off_type; typedef std::mbstate_t state_type; static void assign(_E& _X, const _E& _Y) {_X = _Y; } static bool eq(const _E& _X, const _E& _Y) {return (_X == _Y); } static bool lt(const _E& _X, const _E& _Y) {return (_X < _Y); } static int compare(const _E *_U, const _E *_V, size_t _N) {return (memcmp(_U, _V, _N * 2)); } static size_t length(const _E *_U) { size_t count = 0; while(_U[count] != 0) { count++; } return count; } static _E * copy(_E *_U, const _E *_V, size_t _N) {return ((_E *)memcpy(_U, _V, _N * 2)); } static const _E * find(const _E *_U, size_t _N, const _E& _C) { for(int i = 0; i < _N; ++i) { if(_U[i] == _C) { return &_U[i]; } } return 0; } static _E * move(_E *_U, const _E *_V, size_t _N) {return ((_E *)memmove(_U, _V, _N * 2)); } static _E * assign(_E *_U, size_t _N, const _E& _C) { for(size_t i = 0; i < _N; ++i) { assign(_U[i], _C); } return _U; } static _E to_char_type(const int_type& _C) {return ((_E)_C); } static int_type to_int_type(const _E& _C) {return ((int_type)(_C)); } static bool eq_int_type(const int_type& _X, const int_type& _Y) {return (_X == _Y); } static int_type eof() {return (EOF); } static int_type not_eof(const int_type& _C) {return (_C != eof() ? _C : !eof()); } }; typedef std::basic_string utf16ssortingng; 

Les chaînes sont stockées avec la classe ci-dessus et les données UTF16 brutes sont transmises aux fonctions spécifiques de l'API des différentes plates-formes, qui semblent toutes prendre en charge le codage UTF16.
L'implémentation peut ne pas être parfaite, mais les fonctions append, substr et size semblent fonctionner correctement. Je n'ai toujours pas beaucoup d'expérience avec la manipulation de chaînes en C ++, donc n'hésitez pas à commenter / éditer si j'ai dit quelque chose de manière incorrecte.

La différence entre std :: ssortingngs et char * est que la classe std :: ssortingng utilise des fonctionnalités C ++ et que char * ne fonctionne pas. Un std :: ssortingng est une classe de conteneur de caractères et définit des méthodes pratiques pour l’utiliser, un char * est un pointeur sur une mémoire avec laquelle vous pouvez travailler.

Si vous recherchez une classe de base indépendante de la plate-forme, je vous dirigerai vers QSsortingng . Cela fait partie de la bibliothèque Qt qui vise à atteindre des implémentations indépendantes de la plate-forme de C ++. C’est aussi OpenSource , vous pouvez donc l’utiliser pour avoir une idée de la manière dont les autres implémentent des chaînes indépendantes de la plate-forme. La documentation est aussi très bonne

Mettre en œuvre une classe abstraite pour représenter de manière différente sur chaque plate-forme semble une mauvaise idée. Un travail supplémentaire d’implémentation et de test (sur chaque plate-forme) et appenda plus de surcharge que l’utilisation de std :: wssortingng (bien sûr, vous pouvez contrer la surcharge en n’utilisant pas de classe abstraite, mais en utilisant #ifdefs pour changer d’implémentation travail).

Soit en utilisant std :: ssortingng ou std :: wssortingng partout semble être la voie à suivre, implémenter des fonctions utilitaires pour convertir la chaîne que vous choisissez au format dépendant du système et vous n’aurez aucun problème. Je travaille sur un projet multi-plateforme, qui fonctionne déjà sur iOS, Windows, Linux et Mac, dans ce projet j’ai utilisé multibyte std :: ssortingng et je n’ai pas eu beaucoup de problèmes, je n’ai jamais utilisé std :: wssortingng Je vois pourquoi cela ne marcherait pas.