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

SL & STL C++ Discussion :

Convertion std::wstring en char*


Sujet :

SL & STL C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 71
    Par défaut Convertion std::wstring en char*
    Bonjour,

    J'aimerais savoir comment convertir simplement un wstring en char*.

    Merci.

  2. #2
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 71
    Par défaut
    Merci.
    J'ai ajouter les fonctions à mon projet dans un fichier Tool.h
    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
    22
    23
    24
    25
    #include <string>
    #include <locale>
     
     
    namespace Tool {
     
    	std::string WStringToString(const std::wstring& ws)
    	{
    		std::string res(ws);
    		std::locale loc("english");
    		std::use_facet< std::ctype<wchar_t> >(loc).narrow(&ws[0], &ws[ws.length()], '?', &res[0]);
     
    		return res;
    	}
     
    	std::wstring StringToWString(const std::string& s)
    	{
    		std::wstring res(s);
    		std::locale loc("english");
    		std::use_facet< std::ctype<wchar_t> >(loc).widen(&s[0], &s[s.length()], &res[0]);
     
    		return res;
    	}
     
    }
    et j'ai l'erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Erreur	1	tool.h	9	error C2664: 'std::basic_string<_Elem,_Traits,_Ax>::basic_string(std::basic_string<_Elem,_Traits,_Ax>::_Has_debug_it)' : impossible de convertir le paramètre 1 de 'const std::wstring' en 'std::basic_string<_Elem,_Traits,_Ax>::_Has_debug_it'
    Erreur	2	tool.h	18	error C2664: 'std::basic_string<_Elem,_Traits,_Ax>::basic_string(std::basic_string<_Elem,_Traits,_Ax>::_Has_debug_it)' : impossible de convertir le paramètre 1 de 'const std::string' en 'std::basic_string<_Elem,_Traits,_Ax>::_Has_debug_it'
    Pourquoi ?

  4. #4
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par pegase06 Voir le message
    Elle est bien étrange, cette prise d'adresse. Tu références un élément qui n'existe pas pour en prendre l'adresse. J'aurais plutôt fait: .

    Cela ne règle pas ton problème, mais c'est déjà un petit plus.

    Carl

  5. #5
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut 3 erreurs/3 lignes
    Citation Envoyé par pegase06 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	std::string WStringToString(const std::wstring& ws)
    	{
    		std::string res(ws);
    		std::locale loc("english");
    		std::use_facet< std::ctype<wchar_t> >(loc).narrow(&ws[0], &ws[ws.length()], '?', &res[0]);
     
    		return res;
    	}
    }
    Pourquoi ?
    Pourquoi 3 erreurs en 3 lignes, telle est la question.

    Reprenons :

    std::string res(ws);

    Déjà, ça ne risque pas de compiler. Une chaine de char n'est pas une chaine de wchar_t. Probablement fallait-il lire

    std::string res(ws.size());

    puisque de toutes façons le contenu sera effacé, il faut juste créer les caractères à écraser.

    std::locale loc("english");

    Qui dit qu'une telle locale existe? Sur un système Un*x, je ne pense pas que risque d'être le cas. Peut-être une locale "en" existera t-elle, mais en quoi en avons nous besoin?

    Surtout que doit faire une telle "locale"? La "locale" devrait regrouper les caractéristiques locales. En quoi les facets ctype et codecvt sont-elles des propriétés locales (= préférences régionales)? En rien évidemment. Ce sont des caractéristiques de jeux de caractères. Bien sûr, ISO-8859-5 ne permet pas d'écrire le français, et "donc" ne se trouvera pas dans une locale française ("fr", "fr_FR", "french"...). Mais, en réalité, ISO-8859-1 non plus. La relation entre locale et jeu de caractères est complexe et dépendant de l'histoire. On trouve d'ailleurs des locales appelée "fr.utf8". Ridicule.

    Cette absurdité prend racine quelque part dans Unix. C++ a suivit dans la voie du non-sens et de l'inutilisable, évidemment.

    En résumé : le nom des locales est dépendant du système et, en terme de jeu de caractère, sa signification peu claire. De toutes façons, le jeu de caractère est une propriété d'un ressource (fichier, flux, chaine...), pas d'une région/culture (mais un utilisateur peut typiquement avoir un codage préféré pour les fichiers de sortie).

    Ici, la ressource en entrée est une chaine large, donc normalement composée de code-point Unicode : UCS-2 ou UCS-4. (Mais on risque aussi de trouver de l'UTF-16. Beurk. Encore une question à préciser.) Le codage est donc à peu-près clair (nous verrons que non, pas tout à fait).

    En sortie par contre, il faudrait définir le jeu de caractère à utiliser : est-ce défini par un protocole (= une norme), par le concepteur du programme, ou par la préférence de l'utilisateur (seul cas où une locale me semble adéquate). Pour les sorties, une variable d'environnement spécifique (qui n'influe pas les autres paramètres de localisation), ou une option en ligne de commande est souvent le seul réglage suffisamment flexible pour s'adapter aux différences de jeux de caractères.

    Enfin, si la locale "english" signifie comme je le pense "iso-latin-1", la conversion est triviale :

    c = wc < 256 : (char)wc : '?';

    En effet les valeurs Unicode correspondent intentionnellement à iso-latin-1, pour la bonne notion de correspondance : encore faut-il être en forme NFC (ou NFKC...), c'est à dire qu'une lettre doit être décrite par un seul code-point, par exemple : "à" doit être codée LATIN SMALL LETTER A WITH GRAVE et non LATIN SMALL LETTER A suivit de COMBINING GRAVE ACCENT.

    Je ne sais pas ce que font les implémentations de codecvt des formes D (LATIN SMALL LETTER A suivit de COMBINING ACUTE ACCENT) mais la norme dit bien qu'elles n'ont pas à les gérer, pas plus qu'un wchar_t en UTF-16 (puisque la représentation interne ne doit pas avoir plusieurs "éléments" (wchar_t) pour une séquence d'éléments externes, représentant une lettre). Manifestement, ce genre de choses n'est pas prévu, pour preuve l'interface utilisée ici : narrow.

    Je mentionne ça en passant, il faut s'assurer quand on parle de wstring si :
    - il s'agit bien d'UCS-* (comme on l'attend pour une représentation interne) ou d'UTF-16 (comme Java, assez hypocritement)
    - on exige la forme NFC (forme "courte"), NFD, ou n'importe; mais très franchement les diacritiques combinant sont une débilité sans nom inventée par Unicode, je n'imagine pas que votre code soit compatible avec ça (en faisant quelque traitement - autre que lire un chaine recopier la chaine) (les code-point combinant Unicode DOIVENT MOURIR, faites passer le mot) (reste qu'ils ne sont pas encore mort - et à peine nés)

    En général on fait les deux hypothèses ci-dessus sans le dire, mais c'est quand même un beau bordel (et passablement hypocrite aussi).

    Dans la ligne :

    std::use_facet< std::ctype<wchar_t> >(loc).narrow(&ws[0], &ws[ws.length()], '?', &res[0]);

    2 erreurs

    &ws[0], &ws[ws.length()]

    Il n'est pas garanti que la représentation d'une string soit contigüe (contrairement à vector).

    &res[0]

    Même problème, il n'est pas garanti que &res[0], &res[0] + res.size() soit une range valide.

    En plus, &ws[ws.length()] désigne un NUL à la fin de la chaine uniquement parce que ws est const. C'est une idée hyper-vicieuse de la norme et c'est hyper-dangereux : si, dans une évolution future du programme, ws devenait non-const (par exemple, si ça devenait une variable locale de la fonction), le code casserai, silencieusement.

    Non seulement c'est immensément crétin de la part de la norme de différencier const/non-const comme ça, en plus, la description ne veut rien dire :

    the const version returns charT()

    D'après la norme, cette fonction renvoie une référence sur un temporaire! Lapsus normatif? (genre, je ne spécifie pas du tout ce qui est immonde (vector<bool>), ou alors n'importe comment (ici)).

    Fonctionnalité à éviter absolument en tous cas. La surcharge de const ne sert part à ça! (quelque fois, la lib standard ne comprend comment les fonctionnalités du C++ sont censées être utilisées)

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 391
    Par défaut
    Il me semblait bien que ce code était mauvais quand je l'ai vu dans la FAQ.

    Si je me souviens bien, la norme définit seulement deux noms de locale: "C" et "" (chaîne vide).
    Ensuite, les auteurs de la SL se sont bien débrouillés pour qu'il n'y ait absolument aucun moyen d'obtenir un accès direct en écriture sur le buffer d'une std::string (contrairement à ceux de MFC qui proposent CString::GetBuffer()).

    Donc, si je comprends bien, il est:
    • D'une part, impossible de convertir en un seule passe une string en wstring avec un seul appel de narrow() (on doit faire des append() successifs, ou passer par un buffer),
    • D'autre part, impossible de spécifier de manière portable une locale (mais "" devrait suffire dans la plupart des cas).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Donc, si je comprends bien, il est:
    • D'une part, impossible de convertir en un seule passe une string en wstring avec un seul appel de narrow() (on doit faire des append() successifs, ou passer par un buffer),
    narrow c'est un appel virtuel (à l'intérieur), je doute que tu veuille faire un appel par caractère!

    Ceci vaut aussi pour ctype<charT>, codecvt. On accumule quelques caractères dans un buffer avant d'appliquer l'opération (virtuelle). C'est aussi le principe de streambuf. Le buffer va typiquement être de taille fixe, et l'opération répétée en boucle (donc ça n'induit aucune limite sur la quantité de données traitées).

    Note : Il ne faut pas dramatiser le coup des fonctions virtuelles. Juste que par rapport à convertir ou classifier 1 caractère, c'est monstrueusement couteux. (Non, je ne vais pas m'amuser à faire des tests pour le prouver.)

    Encore une fois, si c'est pour convertir de UCS-* (NFC) en ISO-8859-1, il y a plus simple (et efficace et fiable)!

    (Encore une fois, si ce n'est pas du NFC (ou NFKC...), la bibliothèque standard n'est pas utilisable. Si tu importes de l'Unicode de l'extérieur, fais attention à ça.)

  8. #8
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par corrector Voir le message
    Il n'est pas garanti que la représentation d'une string soit contigüe (contrairement à vector).
    En pratique, et pour le futur, c'est garanti :
    http://www.open-std.org/jtc1/sc22/wg...fects.html#530

    Edit : La partie indentée de ce message est n'importe quoi. Merci de n'en pas tenir compte.
    Citation Envoyé par corrector Voir le message
    the const version returns charT()

    D'après la norme, cette fonction renvoie une référence sur un temporaire! Lapsus normatif? (genre, je ne spécifie pas du tout ce qui est immonde (vector<bool>), ou alors n'importe comment (ici)).

    Fonctionnalité à éviter absolument en tous cas. La surcharge de const ne sert part à ça! (quelque fois, la lib standard ne comprend comment les fonctionnalités du C++ sont censées être utilisées)
    Il semble qu'elle connaisse tout de même un peu le langage...
    Citation Envoyé par Le standard, 12.2.5
    The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference except as specified below.
    Fin d'édit

    Pour le vector<bool>, qu'est-ce qui n'est pas spécifié ? Pour moi, ils ont voulu trop spécifier justement, et c'est tombé à côté...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  9. #9
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2008
    Messages
    439
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 439
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    En pratique, et pour le futur, c'est garanti :
    http://www.open-std.org/jtc1/sc22/wg...fects.html#530
    Précisément, non :

    Proposed resolution:

    Add the following text to the end of 21.3 [basic.string], paragraph 2.

    The characters in a string are stored contiguously, meaning that if s is a basic_string<charT, Allocator>, then it obeys the identity &*(s.begin() + n) == &*s.begin() + n for all 0 <= n < s.size().

    Le NUL terminal n'est pas in la chaine et ws.length() n'est pas strictement inférieur à ws.size(), donc &ws[0], &ws[ws.length()] n'est pas une range valide, et la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::use_facet< std::ctype<wchar_t> >(loc).narrow(&ws[0], &ws[ws.length()], '?', &res[0]);
    est incorrecte.

    Citation Envoyé par JolyLoic Voir le message
    Il semble qu'elle connaisse tout de même un peu le langage...
    Je ne pense pas. Et je ne comprends pas ce que tu dis : est-ce que tu penses que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    const int &f () {
      return int();
    }
    est correct?

    La norme (je prends le dernier draft n2521) n'est pas de cet avis, dans le paragraphe que tu cites, 12.2/5 (pas 12.2.5) :
    The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except as specified below. (...) A temporary bound to the returned value in a function return statement (6.6.3) persists until the function exits.
    En dehors de la tournure très surprenante ("A temporary bound to a reference", répété plusieurs fois, alors que le paragraphe commence par "a reference is bound to a temporary", ce qui est la terminologie normale), il me semble très clair. Si ce n'est pas assez clair, quelque chose comme cela devrai être écrit :

    When a reference return value is bound to a temporary, the temporary persists until the function exits.

    (J'ai du relire plusieurs fois la phrase originale; quelle idée d'écrire comme ça? Savent-ils écrire en anglais?)

    Citation Envoyé par JolyLoic Voir le message
    Pour le vector<bool>, qu'est-ce qui n'est pas spécifié ? Pour moi, ils ont voulu trop spécifier justement, et c'est tombé à côté...
    Justement, dans la norme, rien, à part des déclarations. On ne sait pas ce à quoi sert reference::flip(). Comme il n'y a aucune relation explicitée entre vector<bool> et la forme de base de vector, on ne sait ce que fait aucune fonction membre.

Discussions similaires

  1. char * vers std::wstring
    Par chronos dans le forum SL & STL
    Réponses: 7
    Dernier message: 12/09/2007, 09h44
  2. [T-SQL]convert champ binaire en char
    Par arona dans le forum Sybase
    Réponses: 5
    Dernier message: 31/07/2006, 12h57
  3. std::cout et std::wstring
    Par glKabuto dans le forum SL & STL
    Réponses: 11
    Dernier message: 10/06/2006, 18h44
  4. (Problème avec...) conversion de std::string en char
    Par crossbowman dans le forum SL & STL
    Réponses: 7
    Dernier message: 05/03/2006, 19h54
  5. cannot convert 'std::string' to 'System::String ^'
    Par broadhead dans le forum MFC
    Réponses: 1
    Dernier message: 14/06/2005, 11h37

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