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

Langage C++ Discussion :

convertir un TCHAR* en char *


Sujet :

Langage C++

  1. #1
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut convertir un TCHAR* en char *
    Bonjour

    J'ai un souci de conversion d'un TCHAR * vers un char *
    J'ai un peu abandonné C++ au profit de C# depuis quelques années et je me perds un peu dans certaines conversions de type

    Mon application doit utiliser un des agument passé a l'appel de l'exe
    Ces arguments sont des TCHAR *

    Mais la fonction WriteFile (qui écrit sur mon port com) attends un char *

    J'avais cru qu'un simple cast suffirait, mais je réalise que comme le TCHAR * est vraissemblablement un tableau de WORD, le byte de poids fort de mon primer WORD est interpreté comme le null terminator du string

    Résultat mon cast me rends seulement le premier caractére du TCHAR *
    Comment puis-je résoudre cela en C ?
    Existe-il des fonction de conversion ou bien faut il le faire a la main dans une boucle de parcours du TCHAR * ?


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int _tmain(int argc, _TCHAR* argv[])
    {
      LPCTSTR portname = L"COM5:";
      int len=0;
      DWORD result=0;
      char *buffer;
      DWORD dw;
      buffer=(char *)argv[1];
      len=strlen(buffer);
      WriteFile(hComm, buffer, len, &result, NULL);

    Merci de votre aide
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  2. #2
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    hello,

    writefile écrit des bytes, pas des caractères, peu importe que ce soit des char ou wchar (TCHAR est le typedef de l'un ou l'autre selon le contexte). Cette fonction attend donc un void*, pas un char*.

    le pb doit être du côté de strlen, je pense, qui elle attend un char*. Il faut la remplacer par la fonction spécifique au wchar (wcslen, il me semble).
    Ensuite dans le paramètre 3 de writefile, le nombre de bytes à écrire, tu multiplies la longueur obtenue par la taille de WCHAR.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    int _tmain(int argc, _TCHAR* argv[])
    {
      LPCTSTR portname = L"COM5:";
      int len=0;
      DWORD result=0;
      TCHAR *buffer;
      DWORD dw;
      buffer=argv[1];
      len=wcslen(buffer);
      WriteFile(hComm, buffer, len*sizeof(TCHAR), &result, NULL);
    }

  3. #3
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Merci stendhal666

    Mais le problème n'est pas lié a la longueur
    bien que si on n'est pas prévenu c'est aussi facile de tomber dans le panneau de

    Qui rends une longueur virtuelle qui ne correspond pas a la réalité physique

    Le problème c'est que je dois VRAIMENT envoyer des char, mon CreateFile ouvre le port com et ce ne sont pas des _TCHAR qui sont attendus

    Comme ca commençait a m'énerver toutes ces histoires de conversions brumeuses et mal documentées, j'ai fini par écrire une petite methode qui fait le travail

    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
    char *ConvertToCharPtr(_TCHAR* tc)
    {
      int ltc=_tcslen(tc);
      char *buf=(char *)calloc(ltc+2,1);
      char *p;
      char c;
      p=buf;
      int i=0;
      for (i=0;i<ltc;i++)
      {
        c=(char)tc[i];
        *p=c;
        p++;
     
      }
      return buf;
    }
    Mais quand on a fait du cSharp pendant des années le traitement de ces nouveaux Types en C++ est vraiment déroutante
    A la limite je préfere encore le bon vieux C ou meme l'assembleur, au moins on sait a quoi s'attendre et on ne doit pas chipoter avec une couche de pseudo abstaction hétéroclite !
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par olibara Voir le message
    Qui rends une longueur virtuelle qui ne correspond pas a la réalité physique
    Cela peut être normal. Et d'ailleurs il ne faut jamais faire de prédiction de taille avec les chaînes de caractères

    Avec de l'unicode, un caractère peut être codé sur plusieurs octets
    Même avec certains code page étendu (sur 2 octets)


    Citation Envoyé par olibara Voir le message
    Le problème c'est que je dois VRAIMENT envoyer des char, mon CreateFile ouvre le port com et ce ne sont pas des _TCHAR qui sont attendus
    Dans un autre sens tu envoies des 0 et des 1

    Citation Envoyé par olibara Voir le message
    Comme ca commençait a m'énerver toutes ces histoires de conversions brumeuses et mal documentées, j'ai fini par écrire une petite methode qui fait le travail
    La MSDN de Microsoft donne également les fonctions de conversions entre les TCHAR, WCHAR, LPSTR, LPWSTR, LPCTSTR ...

    Comment : effectuer une conversion entre différents types de chaînes


    Citation Envoyé par olibara Voir le message
    Mais quand on a fait du c Sharp pendant des années le traitement de ces nouveaux Types en C++ est vraiment déroutante
    Détrompe toi TCHAR, WCHAR, LPSTR, LPWSTR,LPCTSTR.... ce sont des types spécifiques Windows créés par Microsoft qui date de 1995.

    En C on a seulement les char et les wchar

    Édit: Le problème ici c'est que ton TCHAR* peut contenir de l'unicode et ne pas avoir de conversion vers de l'ASCII ( ton char*)

  5. #5
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Cela peut être normal. Et d'ailleurs il ne faut jamais faire de prédiction de taille avec les chaînes de caractères

    Avec de l'unicode, un caractère peut être codé sur plusieurs octets
    Même avec certains code page étendu (sur 2 octets)
    Raison de plus pour disposer d'une fonction qui peut donner la taille physique réelle de la chaine

    Dans un autre sens tu envoies des 0 et des 1
    Non ! je dois envoyer un traditionnel str composé d'un tableau de char null terminated
    Oui ! un char c'est une combinaison de 8 bit a 0 ou 1


    La MSDN de Microsoft donne également les fonctions de conversions entre les TCHAR, WCHAR, LPSTR, LPWSTR, LPCTSTR ...
    J'ai passé plus de temps a chercher cela sans succès que d'écrire moi même une méthode
    Mais si la méthode existe je suis toujours preneur pour la connaitre

    Merci pour ton aide
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    En théorie c'est la fonction wcstombs

    Mais
    1. Elle est dépréciée au profit de la méthode wcstombs_s. C'est la méthode sécurisée (le petit s à la fin)
    2. Si ton TCHAR n'est pas Unicode cette méthode n'est pas la bonne, et un cast ou une recopie suffit. Son nom l'indique Wide Char String To Multi-Byte String (Unicode vers code page)



    Mais je pensais à un truc puisque c'est l’Unicode qui pose problème, pourquoi ne pas le supprimer et tout passer en ASCII si cela est possible.
    Style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main(int argc, char** argv)
    {
    // ....
     
        return 0;
    }

  7. #7
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Mais je pensais à un truc puisque c'est l’Unicode qui pose problème, pourquoi ne pas le supprimer et tout passer en ASCII si cela est possible.


    Ben non !
    J'y avais pensé

    A la compilation ça passe très bien
    Mais à l’exécution ça foire

    Parce que le paramètre passé par l'environnement (Windows CE en l’occurrence) est un unicode
    Donc si je donne un paramètre Style "Ma Chaine de Char" :

    Le argv[1] en char * donnera 'M'
    Puisque qu'en réalité ce que contient argv[1] c'est

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    (char) 'M'
    (char) '\0'
    (char) 'a'
    (char) '\0'
    (char) ' '
    (char) '\0'
    (char) 'C'
    etc..

    Donc le deuxième char sera interprété comme end de la chaine argv[1].

    Accessoirement je trouve ce débat particulièrement intéressant parce qu'il confirme ma première impression qui est qu'en réalité peu de développeurs maitrisent ces subtilités dont les solutions se trouvent a la débrouille

    Et en pratique ma méthode ConvertToCharPtr(_TCHAR* tc) a l'avantage d’être explicite
    Faute de mieux, je considère que c'est la moins pire des solutions.
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par olibara Voir le message
    Et en pratique ma methode ConvertToCharPtr(_TCHAR* tc) a l'avantage d'etre explicite
    Faute de mieux, je considere que c'est la moins pire des solutions.
    Non ta fonction est mauvaise

    Il n'y a que de l'UTF-8 qui peut être caster en ASCII et rien qu'en ASCII.
    Donc cela foire
    1. Si tu as un accent ou un caractère non ASCII (*)
    2. Si ton OS ne manipule pas de l'UTF-8, mais de UTF-16 - UTF-32 ou autre


    * -> Si la fonction wcstombs retourne un Multi-Byte String c'est sûrement parce qu'elle essayera de retourner une chaîne Latin-1 ou Latin-9 si les caractères non ASCII sont gentils et connus

    Édit:
    Citation Envoyé par olibara Voir le message
    Accessoirement je trouve ce débat particulièrement intéressant parce qu'il confirme ma premiere impression qui est qu'en réalité peu de développeurs maitrisent ces subtilités dont les solutions se trouvent a la débrouille
    Quoique tu penses Microsoft fourni toutes les fonctions de conversion ... mais en plusieurs exemplaires dans ATL, MFC, en standard ...
    Tu ne trouves pas que c'est un peu normal
    1. Il y a plusieurs Unicode: au moins 3. Donc rien que cela il faut les gérer, au moins 2. Si je ne dis pas de bêtises le passage de l'un vers l'autre est plus au moins facile.
    2. L'ASCII c'est seulement 255-256 caractères. L'Unicode c'est X 000 caractères.
    3. Il y a ASCII mais il y a surtout les code pages (ou MBCS). Le problème des code pages c'est qu'elles ne sont pas toutes standardisées.


    Donc il faut être plus ou moins sûr qu'on ait que de l'ASCII ou une code page gentille lorsqu'on fait une conversion ASCII vers l’Unicode, ou vice et versa.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Le mieux en C++, si tu n'utilises pas MFC dans le projet, c'est de faire des fonctions surchargées pour convertir sans avoir besoin de compilation conditionnelle:

    Chez moi, j'ai fais ces quatre fonctions:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //StringConversions.hpp
     
    //Convertir de n'importe laquelle vers wstring
    std::wstring GetWString(std::string const &);
    std::wstring GetWString(std::wstring const &);
    //Convertir de n'importe laquelle vers string
    std::string GetAString(std::string const &);
    std::string GetAString(std::wstring const &);
     
    //Convertir de n'importe laquelle vers le type qui correspond à une string de TCHAR.
    #ifdef UNICODE
    #define GetTString GetWString
    #else
    #define GetTString GetAString
    #endif
    Code C++ : 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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    //StringConversions.cpp
    #include "StringConversions.hpp"
     
    #include <cwchar>
    #include <string>
    #include <vector>
    #include <exception>
    using namespace std;
     
    wstring GetWString(string const &src)
    {
    	size_t cchBufSize = 0;
    	errno_t err = mbstowcs_s(&cchBufSize, NULL, 0, src.c_str(), _TRUNCATE);
    	if(err != 0)
    		throw std::runtime_error("Failed to get size of output when converting to wstring.");
     
    	vector<wchar_t> vec(cchBufSize);
    	err = mbstowcs_s(&cchBufSize, &vec.at(0), cchBufSize, src.c_str(), cchBufSize-1);
    	if(err != 0)
    		throw std::runtime_error("Failed to convert to wstring.");
    	wstring ret(&vec.at(0));
    	return ret;
    }
    wstring GetWString(wstring const &src) { return src; }
    string  GetAString(string const &src) { return src; }
    string  GetAString(wstring const &src)
    {
    	size_t cchBufSize = 0;
    	errno_t err = wcstombs_s(&cchBufSize, NULL, 0, src.c_str(), _TRUNCATE);
    	if(err != 0)
    		throw std::runtime_error("Failed to get size of output when converting to string.");
     
    	vector<char> vec(cchBufSize);
    	err = wcstombs_s(&cchBufSize, &vec.at(0), cchBufSize, src.c_str(), cchBufSize-1);
    	if(err != 0)
    		throw std::runtime_error("Failed to convert to string.");
    	string ret(&vec.at(0));
    	return ret;
    }
    Elles ne sont pas optimales niveau performance (elles font une copie de plus que nécessaire), mais sont sûres et normalement, sont exception-safe.

    Leur problème, c'est que je ne sais pas quel encodage wcstombs_s() utilise, vu qu'il n'est pas possible de le préciser en paramètre (je suppose que c'est la System ANSI Code Page, qui correspond généralement à l'encodage Windows-1252). Mais si ça ne convient pas, le code devrait être facile à adapter pour utiliser WideCharToMultiByte() et MultiByteToWideChar() à la place, en précisant l'encodage désiré...
    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.

  10. #10
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Merci a tous

    Dans mon cas je n'ai pas trop de souci car l'environnement est maitrisé et les chaines attendues sont des codes alphanumeriques purs sans accent car il sont destinés a un lecteur de barcode qui ne lit que de l'ASCII

    J'ai par contre apris quelques subtilité si d'aventure je devais a nouveau traiter des chaines en C++
    J'aime bien le C (++ ou non) pour la performance mais quand il faut interfacer avec l'extérieur, cSharp c'est quand meme vachement plus simple !
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  11. #11
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Leur problème, c'est que je ne sais pas quel encodage wcstombs_s() utilise, vu qu'il n'est pas possible de le préciser en paramètre (je suppose que c'est la System ANSI Code Page, qui correspond généralement à l'encodage Windows-1252). Mais si ça ne convient pas, le code devrait être facile à adapter pour utiliser WideCharToMultiByte() et MultiByteToWideChar() à la place, en précisant l'encodage désiré...
    Peut-être que la solution ce sont les méthodes _wcstombs_s_l et/ ou _setmbcp

    Mais il faut tester pour savoir si elles créent une locale temporaire ou modifient celle du système (avec des save et restore si c'est possible)

    Édit: Cela me rappelle le bon vieux temps 2 appels. Le premier avec NULL pour avoir la taille et le deuxième celui effectif. Lorsque tu ne le sais pas et/ ou que MSDN ne le dit pas de façon explicite

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par foetus Voir le message
    Édit: Cela me rappelle le bon vieux temps 2 appels. Le premier avec NULL pour avoir la taille et le deuxième celui effectif. Lorsque tu ne le sais pas et/ ou que MSDN ne le dit pas de façon explicite
    Et C99 a fait la même chose avec snprintf(). J'aimerais tant que Micro$oft cesse enfin de pisser sur les développeurs C, et implémente enfin le standard...
    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.

Discussions similaires

  1. [D7] Convertir un integer en char
    Par raoulmania dans le forum Langage
    Réponses: 11
    Dernier message: 17/08/2008, 11h30
  2. [convertir TCHAR* en char*]
    Par youp_db dans le forum Windows
    Réponses: 2
    Dernier message: 07/03/2008, 16h46
  3. Réponses: 1
    Dernier message: 13/10/2005, 15h10
  4. Convertir un TStrings en char
    Par syphicoque dans le forum C++Builder
    Réponses: 11
    Dernier message: 04/04/2004, 22h59
  5. Réponses: 3
    Dernier message: 02/07/2003, 16h24

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