IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

char*, string et wstring


Sujet :

C++

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut char*, string et wstring
    Bonjour à tous !

    Bon je sais ce que vous pensez : c'est un marronnier... Mais j'ai beau avoir lu une bonne centaine de topics à ce sujet ainsi que la FAQ de developpez.com et pourtant je n'arrive toujours pas à comprendre ce qui se passe dans mon cas...

    Je récupère après une appel à une fonction d'une librairie un .
    Cette variable contient la chaine suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Bibliothèque de « Esteban
    or elle devrait contenir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Bibliothèque de "Esteban
    .

    Je suppose donc qu'il s'agit d'une chaine encodée en UTF-8 avec des caractères de 16bits. Sauf que quand je parcours le tableau de char j'ai la liste suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    char B (66)
    char i (105)
    char b (98)
    char l (108)
    char i (105)
    char o (111)
    char t (116)
    char h (104)
    char(-61) //Le caractère est modifié dans le post il s'agit d'un symbole coché
    char ® (-88)
    char q (113)
    char u (117)
    char e (101)
    char   (32)
    char d (100)
    char e (101)
    char   (32)
    char ¬ (-62)
    char ´ (-85)
    char ¬ (-62)
    char(-96)
    Je m'attendais à avoir les caractères √ et ® regroupés en un seul caractère qui, converti en wchar_t deviendrait un è...

    J'en conclus donc que j'ai rien entravé au truc et que je ne sais absolument pas comment m'en sortir...

    Quelqu'un peut-il m'éclairer un peu s'il vous plait ?

  2. #2
    screetch
    Invité(e)
    Par défaut
    UTF-8 est un encodage a longueur variable, ou les symboles "simples" (a-z et la ponctuation) sont codés sur un seul octet (compatible avec la norme ANSI) et les symboles "complexes" (lettres accentuées spe´cifiques a une langue, idéogrammes et alphabets plus exotiques) sont encodés sur plusieurs octets (de 2 a... 6 je crois)

    la chaîne n'est donc ni une string (qui est seulement ANSI) ni une wstring (qui représente une chaîne UCS-2 ou UCS-4 ou UTF16 selon les cas)

    Ces trucs grossiers (UTF-8, UCS-2 UCS-4 UTF-16, ANSI...) sont des encodages. Les questions sont donc:

    - quel encodage as-tu?
    * tu as de l'UTF-8 dans cet exemple mais cela depend il de la source? d'ou vient cette chaîne?
    - quel encodage veux tu?
    * tu veux de l'encodage naturel de ta machine par exemple?
    * ou bien tout convertir en wstring?
    - quel systeme d'exploitation utilises-tu?


    il se peut que tu doives utiliser des bibliothèques tierces pour que ca marche.

  3. #3
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    C'est compliqué ces histoires d'encodages, je ne suis jamais parvenu à y voir clair. Par exemple, la série des visual studio, depuis la version 7 me semble-t-il, propose une option pour les projets qui est le jeu de carractères (unicode ou multibyte). Qu'est-ce donc que cela?
    Aurais-tu des liens qui expliquent bien ces choses-là?
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut
    Ah ben je commence à mieux comprendre mes problèmes...
    Pour répondre à tes questions :
    -ce cas précis se présente à l'appel de la fonction DNSServiceBrowse de la librairie Bonjour (dns_ns). Je ne connais pas l'encodage, il n'est pas précisé mais je présume que c'est celui du système qui envoie son nom depuis le réseau. Il doit donc y avoir un mélange entre MacRoman dans certains cas et UTF-8 dans d'autres.
    -je veux pouvoir interpréter ces chaines provenant de différents systèmes et encodées dans des formats qui ne me sont pas connus a priori et les mettre dans ma base dans un format string (pas wstring)...
    -je voudrais que mon code soit le même sous Windows, Mac et Linux (ou faire une fonction filtrée par des #ifdef).

    Quelle librairie me suggères-tu ?

    Merci pour vos réponses

  5. #5
    screetch
    Invité(e)
    Par défaut
    dans Windows il y a pour simplifier 2 encodages:

    * l'encodage courant de l'utilisateur qui se traduit par un char*
    * l'encodage appelé a tort Unicode qui est l'encodage UCS-2 (pas le choix), et qui mappe sur des wchar_t de deux octets


    Le flag Multibyte/Unicode permet en fait de changer entre un encodage "local" (par exemple, du francais) et un encodage UCS-2 lors de l'appel des méthodes Windows
    (pour faire simple, les méthodes qui attendent en paramètre des strings recoivent soit des char*, soit des wchat_t*). Utiliser la version MultiByte revient a dire que l'application dépend de la locale courante, et est donc pas "Unicode-aware", donc ne recevra pas l'input windows unicode (si on essaye de taper du chinois, ca marche pô)

    lorsqu'on passe en unicode, tous les paramètres de fonction sont maintenant des wchar_t* donc encodés en UCS-2
    et utiliser la version unicode signifie que l'application doit désormais savoir utiliser l'unicode et recevra désormais l'input sous forme Unicode (donc si on tape du chinois, le charactere chinois sera passé a l'application)

    et il y a quelques fonctions de conversion qui permettent de passer de certains encodages a d'autres.
    par exemple, MultibyteToWideChar peut passer d'une chaine encodée en multibyte (en UTF-8, ou bien dans l'encodage courant) vers de l'UCS-2
    et WideCharToMultiByte fait le contraire.

    Dans une application Widows moderne (sous-entendu, supportant plusieurs langages), l'application doit être reglée en Unicode et traiter la plupart des chaînes en interne en wchar_t, quitte a réinterpreter certaines chaines entrées par l'utilisateur via MultibyteToWideChar.

  6. #6
    Membre confirmé

    Inscrit en
    Août 2007
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 300
    Points : 527
    Points
    527
    Par défaut
    Je pense que screetch couvre complètement votre problème et y apporte les meilleurs solutions (en particulier je recommande effectivement de ne pas avoir de UTF-8/multibyte en stockage interne, le cœur du programme devant être UTF-16/UCS-2 du point de vue Windows, c'est à dire wchar_t/std::wstring du point de vue C++. Oui, j'utilise xxx/yyy, car pour embrouiller tout le monde, il y a en plus des problèmes de synonymes! A quand un nommage "unifié" pour désigner UTF-16/UCS-2? Ah oui, ça existe déjà, ça s'appelle Unicode "sans plus de précision d'encodage" je crois... du moins chez Microsoft, mais bien sûr pas pour les chinois )

    Pour le contexte, Joel Spolsky a pondu dans son style inimitable il y a déjà longtemps un petit texte d'introduction vraiment clair, que je file dans le paquet de bienvenue aux stagiaires. Bien que ce texte soit daté, avec sa seule connaissance, on peut se dépatouiller d'un grand nombre de cas réels.
    "Maybe C++0x will inspire people to write tutorials emphasizing simple use, rather than just papers showing off cleverness." - Bjarne Stroustrup
    "Modern C++11 is not your daddy’s C++" - Herb Sutter

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut
    Formidable merci beaucoup pour toutes ces infos !

    Je vais devoir faire un peu de conception pour m'adapter à ces nouvelles (pour moi) règles. J'ai imprimé le petit article et je vais m'attaquer à des essais. Si je suis bloqué je reviendrai vous voir !

    Merci encore.
    Esteban

  8. #8
    screetch
    Invité(e)
    Par défaut
    salut esteban, j'avais raté ta première réponse car je postais au même moment.
    Sous MacOS je crois (mais je suis pas 100% sûr) que l'API de conversion entre encodages est iconv, comme sous linux et BSD. Avec ca tu peux convertir entre UTF-8 et tout ce que tu veux.
    Et dans le cas Linux/BSD/Solaris il est plutôt conseillé d'utiliser un encodage UTF-8 en interne (car plus compact) et de traduire vers l'encodage utilisé sur la machine si on en a besoin. En fait sous linux avec iconv il est vraiment possible de choisir n'importe quel encodage unicode.
    Dans le cas Windows, c'est wchar_t et donc UCS-2
    dans le cas MacOSX je pense que tu peux choisir aussi, je crois que NSString en interne utilise unichar qui est UCS-2 mais je suis pas 100% sûr.

    Mais disons que l'idée générale pour supporter tout et n'importe quoi, c'est
    input utilisateur -> conversion Unicode (n'importe lequel, le plus pratique) -> traitements, copies, blabla -> conversion Encodage local (Chinois, Japonais, Francais... voire unicode parfois ) -> affichage

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut
    Ok j'entends bien vos conseils et je vais tâcher de bien convertir toutes mes entrées dans un format unique (mettons UTF8) pour ma bdd et de reconvertir les chaines stockées dans le format utilisé par le système pour la restitution.

    En revanche ce que je m'explique moins bien c'est comment je détecte le format en entrée. Mes entrées sont diverses et sont le plus souvent le fait de communications réseau d'origines diverses (Windows, Mac, Linux, Téléphone, etc...), du coup je ne connais pas nécessairement le format d'encodage en entrée. Y a-t-il un moyen de le détecter ou bien je dois le deviner ? Si je convertit ce que je croyais être du MacRoman en UTF8 dans ma bdd et qu'ensuite je le reconverti en UCS-2 pour l'afficher dans l'IHM, je vais afficher des symboles à la con non ?

  10. #10
    screetch
    Invité(e)
    Par défaut
    tes communications réseau, sans en savoir plus, c'est pas possible de savoir en quoi elles sont encodées.
    Si c'est toi qui les contrôle c'est facile, c'est toi qui décide.
    Si ca vient du systeme d'exploitation, ca doit être avec la locale courante. essaye:
    dans un terminal pour avoir l'encodage courant? si c'est de l'UTF-8 il y a des chances que ca soit pour ca que tu recois des chaînes en UTF-8.
    Enfin si ca vient d'une lib externe, il faut voir la doc de cette bibliothèque pour savoir ce qu'elle renvoie.

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut
    Pour compléter mon premier exemple, mettons que je reçoive grâce à la même requête (Service Discovery de Bonjour) 2 chaines provenant pour l'une d'une machine sous Windows 7 et l'autre d'une machine sous Mac OS.

    Il n'est écrit nulle part dans la doc de DNS_SD que la chaine est encodée d'une certaine manière.

    Tout ce que je reçois est un char* dans ma fonction callback. Du coup j'ai 2 options : soit je considère que c'est encodé par la librairie dans l'encodage du système sur lequel tourne la librairie (ce qui serait logique puisque j'imagine mal la même librairie encoder en MacRoman sous Windows), soit je considère que la librairie n'encode rien et qu'elle laisse la chaine telle qu'envoyée par le système qui a répondu... ce qui pourrait signifier que dans un cas j'ai de l'UCS-2 et dans l'autre du MacRoman... Arff je m'en sors pas... Il faut que je fasse des essais de conversion pour en savoir plus.

    Penses-tu simplement qu'il est possible qu'une chaine char* puisse contenir du texte encodé dans des formats 2 octets (UCS-2 par exemple) ?

    Je fais des essais avec iconv et je vous tiens au courant.

  12. #12
    screetch
    Invité(e)
    Par défaut
    a priori non, sous MacOS une chaine UCS-2 est une chaine unichar*
    mais tout est possible hein
    la c'est au dela de mes connaissances, il faut trouver de la doc sur cette bibliothèque ou quelqu'un qui s'en est deja servi et qui sait.

  13. #13
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut
    Mazel'tov !!

    J'ai réussi... et je vais expliquer ici comment j'ai fait, ca pourra aider quelqu'un d'autre et ca vous permettra de me corriger si je dis des bêtises

    Je me suis rendu compte que la chaine en entrée est bien encodée en UTF-8, il fallait donc que je l'encode dans le style local (MacRoman pour moi).

    Le code : c'est inline, je n'ai pas fait de fonction pour le moment
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    char *instr = const_cast<char *>(serviceName);
    char *_strout = new char(strlen(serviceName)*2);
    char *strout = _strout;
     
    size_t nconv = 0;
    size_t instrlen = strlen(serviceName);
    size_t outstrlen = instrlen*2;
     
    iconv_t ic = iconv_open("MACROMAN", "UTF-8");
    if(ic != (iconv_t)-1) {
    	nconv = iconv(ic, &instr, &instrlen, &strout, &outstrlen);
     
    	if(nconv != (size_t)-1) {
    		cout << "strout=" << _strout << endl;
                    delete [] _strout;
    	} else
    	**    cerr << "error : " << errno << "-" << strerror(errno) << endl;
    } else
         cerr << "error : " << strerror(errno) << endl;

  14. #14
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut
    En gros maintenant ce qu'il me reste à faire c'est stocker la chaine reçue sans la modifier puisqu'elle est en UTF-8, et utiliser la conversion à chaque fois que je veux afficher cette chaine...

    C'est bien ca ?

  15. #15
    screetch
    Invité(e)
    Par défaut
    ca dépend de l'affichage. Les NSString de l'API MacOS graphique sont en UCS-2 je crois, mais elles ont le bon goût de faire leur propre conversion
    La console en revanche, ca dépend de la machine utilisateur.
    Note que si toi tu as du MacRoman, a propri un chinois en chine aura pas du MacRoman et qu'il vaudrait mieux effectuer la conversion vers l'encodage "utilisé en ce moment sur la machine". Je ne sais pas trop comment le récupérer.
    Si c'est en graphique alors file le a NSString et laisse le faire

Discussions similaires

  1. char, string, wchar_t, wstring ?
    Par Glân von Brylân dans le forum SL & STL
    Réponses: 8
    Dernier message: 22/10/2014, 22h32
  2. Transtypage int => char, String => char
    Par autregalaxie dans le forum Débuter avec Java
    Réponses: 7
    Dernier message: 10/04/2007, 13h48
  3. string et wstring
    Par superspag dans le forum C++
    Réponses: 7
    Dernier message: 20/01/2006, 08h31
  4. char *, string et tableau statique ou dynamique
    Par salseropom dans le forum C
    Réponses: 2
    Dernier message: 05/12/2005, 11h33
  5. Réponses: 3
    Dernier message: 26/05/2004, 23h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo