Bonjour,
J'aimerais savoir comment convertir simplement un wstring en char*.
Merci.![]()
Bonjour,
J'aimerais savoir comment convertir simplement un wstring en char*.
Merci.![]()
Merci.
J'ai ajouter les fonctions à mon projet dans un fichier Tool.h
et j'ai l'erreur :
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; } }
Pourquoi ?
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'
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:.
Code : Sélectionner tout - Visualiser dans une fenêtre à part &ws[0] + ws.length()
Cela ne règle pas ton problème, mais c'est déjà un petit plus.
Carl
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)
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.
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.)
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.
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.
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
est incorrecte.
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]);
Je ne pense pas. Et je ne comprends pas ce que tu dis : est-ce que tu penses que
est correct?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 const int &f () { return int(); }
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?)
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.
le problème n'est pas la présence du NULL terminal puisqu'une étendue de &ws[0] à &ws[ws.length()] va des éléments de 0 à ws.length()-1 (= ws.size()-1 ), le "end()" d'un itérateur à accès aléatoire pointant sur l'adresse de l'élément se trouvant juste APRES le dernier élément du tableau (élément auquel il ne faut bien sur pas tenter d'accéder). La seule crainte pourrait être que l'opérateur [] dans ws[ws.length()] vérifie que l'indice soit strictement plus petit que ws.length() (et lève une exception dans le cas contraire), mais cela m'étonnerais, surtout si cela est implémenté comme pourIl faudrait juste voir ce que défini la norme sur l'operateur [] pour les basic_stringClause 23.3.4 [multiset] defines operator[] as data()[pos]
(Tu voulais dire NUL, je suppose.) Je n'ai jamais parlé de la présence de NUL.
Cette étendue (range) n'est pas valide, elle n'existe pas, comme je l'ai indiqué.
Elle ne va nul part puisqu'elle n'existe pas.
Rappelons que le code est :
Où vois-tu "end()"?
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]);
Ou un même un itérateur "juste APRES le dernier élément" ("one-past-the-end")?
Non, elle ne va pas faire cela parce que l'indice n'a pas à être strictement inférieur à ws.length(). L'expression &ws[ws.length()] est absolument légale, comme je l'ai indiqué (mais elle est aussi très fortement déconseillée).
Clause 23.3.4 [multiset] defines operator[] as data()[pos]
23.3.4 fait 4 pages! (je regarde n2315, là) Tu peux préciser?
Et depuis quand multiset définit data()?
Par contre, à la question : est-ce que string peut faire des vérifications de bornes dans operator[], la réponse est oui, bien sûr.
Comment ça? Si une fonction n'est pas spécifiée, on ne peut pas l'utiliser!
Dès lors qu'une fonction exige que ses arguments soient dans un certain domaine, l'implémentation de la fonction peut bien évidemment le vérifier.
Tu es sûr que Visual C++ le fait toujours et pas simplement dans la configuration par défaut? Tu es sûr que la libc++ ne peut pas le faire avec les -D qui vont bien?
Solution : préciser la question.
Qu'a t-on en entrée, que veut-on en sortie?
Voir aussi mon premier message (#5) à propos d'UCS-*/UTF-16 et NFC/NFD.
Pour vector (a vérifier pour les autres), visual utilise un test, mais on peut le désactiver. Gcc n'en fait pas. Du moins dans les dernière source que j'ai regardé : visual 2005 et gcc 3.4
Pour être plus précis,dans la norme, l'operateur [] ne spécifie pas si il doit y avoir ou non un test..
Pour être encore plus précis, si les arguments d'une fonction ne sont pas dans son domaine, sauf mention contraire, le comportement est indéfini. Autrement dit, c'est une précondition : tu dois passer les bon arguments, dans le cas contraire, tu ne peux rien exiger parce que tu as rompu ton contrat.
Je parlais du fait que le stockage soit continu, comme sur un vecteur. Pour ce qui est de l'accès à &ws[ws.length()], on est d'accord sur le fait que ce soit une erreur. Ce serait aussi une erreur pour un vecteur, la bonne écriture étant &ws[0] + ws.size()
Non, j'ai dit n'importe quoi. On va mettre ça sur le dos de l'heure tardive.
A tête un peu plus reposée, je dirais juste que c'est une notation pour indiquer que le fonction retourne une référence constante à un caractère nul. A l'implémentation de se débrouiller pour que ce soit une référence valide.
Ils ont un peu amélioré ça dans le brouillon du prochain standard, mais pour moi et pour beaucoup, l'erreur est d'avoir spécialisé vector<bool>, tout simplement :
Envoyé par Le brouillon du standard
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.
Je préfère ws.data() + ws.size(), ça marche même si wc est vide.
Dans le brouillon de norme N2315, data est aussi défini pour vector (23.2.5.3 [vector.data]).
Mettre quoi sur le dos de l'heure tardive?
Notation pourrie.
Effectivement : pour tout T, vector<T>::reference est une reference, donc vector<T>::operator[] renvoie une lvalue, sauf pour T = bool.
De plus, dans la table des matières du brouillon de norme (N2315) :
23.2.5 Class template vector
23.2.6 Class vector<bool>
ce n'est pas la même section!
Partager