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

FAQ VC++ et MFCConsultez toutes les FAQ

Nombre d'auteurs : 20, nombre de questions : 545, dernière mise à jour : 5 avril 2013  Ajouter une question

 

Cette faq a été réalisée pour répondre aux questions les plus fréquement posées sur le forum Développement Visual C++

Je tiens à souligner que cette faq ne garantit en aucun cas que les informations qu'elle contient sont correctes ; Les auteurs font le maximum, mais l'erreur est humaine. Si vous trouvez une erreur, ou si vous souhaitez devenir redacteur, lisez ceci.

Sur ce, je vous souhaite une bonne lecture. Farscape

SommaireCString et Conversions (17)
précédent sommaire suivant
 

Si vous développez des ActiveX ou objets COM avec Visual C++, vous allez devoir utiliser les BSTR lors de manipulation de chaînes de caractères.
Le type BSTR (Basic STRing) est un pointeur de 32 bits (comme tous les pointeurs) qui pointe vers un tableau de caractères UNICODE.
En représentation UNICODE, 1 caractère est codé sur 2 octets, alors qu'en ASCII, 1 caractère est codé sur 1 octet.
Ce type est utilisé par Automation pour la manipulation de chaînes de caractères. Il est défini dans les spécifications d'OLE 2.0 comme

Code C++ : Sélectionner tout
typedef OLECHAR FAR* BSTR;
Avec un type comme celui-ci, on se demande souvent comment s'en servir dans son code C++

Voici deux fonctions utilisant l'api Windows pour le transtypage en char* :

Code C++ : Sélectionner tout
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
void BSTRtoASC (BSTR str, char * &strRet) 
{ 
    if ( str != NULL ) 
    { 
        unsigned long length = WideCharToMultiByte (CP_ACP, 0, str, SysStringLen(str), 
                                            NULL, 0, NULL, NULL); 
        strRet = new char[length]; 
        length = WideCharToMultiByte (CP_ACP, 0, str, SysStringLen(str),  
                           reinterpret_cast <char *>(strRet), length, NULL, NULL); 
        strRet[length] = '\0'; 
    } 
} 
  
void ASCtoBSTR (char * str, BSTR * strRet) 
{ 
    if ( str != NULL ) 
    { 
        unsigned long length = strlen(str); 
        int ResultLength = MultiByteToWideChar (CP_ACP,MB_PRECOMPOSED, 
                           reinterpret_cast <char *>(str),length,NULL,0); 
        *strRet = SysAllocStringLen( NULL, ResultLength); 
        MultiByteToWideChar (CP_ACP,MB_PRECOMPOSED, 
                           reinterpret_cast <char *>(str),length,*strRet,ResultLength); 
    } 
}
Si on utilise des CString MFC, voici une manière très simple de créer un BSTR :
Code C++ : Sélectionner tout
1
2
CString strResult("un test de chaîne"); 
return strResult.AllocSysString();

Mis à jour le 5 avril 2013 nico-pyright(c)

La classe CString dispose de l'opérateur (const char *), de ce fait toutes les fonctions C disposant d'une signature const char * peuvent être utilisées.
Exemple de conversions d'une CString en différents types de données :
Cet exemple est adapté d'un code trouvé sur MSDN pour la fonction strtoul.

Code C++ : Sélectionner tout
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
   char  *stopstring; 
   double x; 
   long   l; 
   int    base; 
   unsigned long ul; 
  
   CString string="3.1415926This stopped it"; 
  
   x = strtod( string, &stopstring ); 
   TRACE( "string = %s\n",(const char *)string ); 
   TRACE("   strtod = %f\n", x ); 
   TRACE("   Stopped scan at: %s\n\n", stopstring ); 
  
   string = "-10110134932This stopped it"; 
   l = strtol( string, &stopstring, 10 ); 
   TRACE( "string = %s",(const char *)string ); 
   TRACE("   strtol = %ld", l ); 
   TRACE("   Stopped scan at: %s", stopstring ); 
  
   string = "10110134932"; 
   TRACE( "string = %s\n",(const char *)string ); 
   /* Convert string using base 2, 4, and 8: */ 
   for( base = 2; base <= 8; base *= 2 ) 
   { 
      /* Convert the string: */ 
      ul = strtoul( string, &stopstring, base ); 
      TRACE( "   strtol = %ld (base %d)\n", ul, base ); 
      TRACE( "   Stopped scan at: %s\n", stopstring ); 
   }
résultats:

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
string = 3.1415926This stopped it 
   strtod = 3.141593 
   Stopped scan at: This stopped it 
 
string = -10110134932This stopped it   strtol = -2147483647   
   Stopped scan at: This stopped itstring = 10110134932 
 
   strtol = 45 (base 2) 
   Stopped scan at: 34932 
   strtol = 4423 (base 4) 
   Stopped scan at: 4932 
   strtol = 2134108 (base 8) 
   Stopped scan at: 932
Autre possibilité utiliser la STL et la gestion des flux avec istringstream

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <sstream> 
template<typename T> 
bool ConvertCString( const CString & Str, T & Dest ) 
{ 
    // créer un flux à partir de la chaîne donnée 
    std::istringstream iss( static_cast<const char *>( Str) ); 
    // tenter la conversion vers Dest 
    return iss >> Dest != 0; 
} 
CString str="25"; 
int nInt; 
ConvertCString( str, nInt ); 
//ou 
ConvertCString( "25", nInt );// fonctionne aussi ...
Cette dernière version est adaptée d'un post de la FAQ C++.

Mis à jour le 22 janvier 2007 farscape

Conversion d'une CString vers une std::string :

Code C++ : Sélectionner tout
1
2
CString str("Bonjour"); 
std::string s((LPCTSTR)str);

Conversion d'une std::string vers une CString :

Code C++ : Sélectionner tout
1
2
   std::string s("Bonjour"); 
   CString str(s.c_str());

Mis à jour le 5 avril 2013 farscape

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//*************************************************************************** 
// Change la base d'une valeur sous forme de chaîne. 
//*************************************************************************** 
CString COutils::ChangeBase(CString Value, int BaseFrom, int BaseTo) 
{ 
    CString ValBaseChanged; 
  
    if (!( BaseFrom <2 || BaseFrom >36 || BaseTo <2 || BaseTo >36) ) 
    { 
        char *StopScan= NULL; 
        char StrBaseOut[250]; 
        intValIn= 0; 
        //Merci nico-pyright(c)  
        ValIn = strtol(Value.GetBuffer(0), &StopScan, BaseFrom); 
        _itoa(ValIn, StrBaseOut, BaseTo); 
  
        ValBaseChanged = CString(StrBaseOut, strlen(StrBaseOut)); 
    } else { 
        ValBaseChanged = "Invalid Base Number"; 
    } 
    return ValBaseChanged; 
}
Pour convertir une chaîne Hexa en entier il suffit juste d'utiliser strtol : voir FAQ: Comment convertir une CString en int, double, long ?

Code C++ : Sélectionner tout
1
2
3
4
5
char *StopScan= NULL; 
  
intValIn= 0; 
//Merci nico-pyright(c) 
ValIn = strtol(Value.GetBuffer(0), &StopScan, BaseFrom);

Remarque : transformer un int en string hexa peut être fait grâce à la fonction format de CString :

Code C++ : Sélectionner tout
1
2
3
4
CString StrHexa; 
int Val = 125; 
  
StrHexa.Format("%X",Val);

Mis à jour le 4 avril 2005 matazz

On trouve la réponse dans le code de la classe CString avec la fonction AllocBuffer qui est utilisée pour allouer la mémoire nécessaire :

Code C++ : Sélectionner tout
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
40
41
42
43
44
45
void CString::AllocBuffer(int nLen) 
// always allocate one extra character for '\0' termination 
// assumes [optimistically] that data length will equal allocation length 
{ 
    ASSERT(nLen >= 0); 
    ASSERT(nLen <= INT_MAX-1);    // max size (enough room for 1 extra) 
  
    if (nLen == 0) 
        Init(); 
    else 
    { 
        CStringData* pData; 
#ifndef _DEBUG 
        if (nLen <= 64) 
        { 
            pData = (CStringData*)_afxAlloc64.Alloc(); 
            pData->nAllocLength = 64; 
        } 
        else if (nLen <= 128) 
        { 
            pData = (CStringData*)_afxAlloc128.Alloc(); 
            pData->nAllocLength = 128; 
        } 
        else if (nLen <= 256) 
        { 
            pData = (CStringData*)_afxAlloc256.Alloc(); 
            pData->nAllocLength = 256; 
        } 
        else if (nLen <= 512) 
        { 
            pData = (CStringData*)_afxAlloc512.Alloc(); 
            pData->nAllocLength = 512; 
        } 
        else 
#endif 
        { 
            pData = (CStringData*) new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)]; 
            pData->nAllocLength = nLen; 
        } 
        pData->nRefs = 1; 
        pData->data()[nLen] = '\0'; 
        pData->nDataLength = nLen; 
        m_pchData = pData->data(); 
    } 
}
La longueur maximale est donc égale à INT_MAX -1 avec INT_MAX = 2147483647 Soit 2 Go . Au passage on remarquera le traitement différent quand le bloc de mémoire à allouer est inférieur à 512 octets.
Notez aussi le traitement différent dans le cas du mode release et debug qui peut expliquer que certains bogues de mémoire n'apparaissent pas en release.

Mis à jour le 4 avril 2005 farscape

Classiquement cette opération pourrait être réalisée avec la fonction C strtok.

Mais celle-ci à l'inconvénient de perturber la chaîne d'origine et de ne pas fonctionner dans certains cas :

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
CString str = "aaa,bbb,ccc,,123"; 
CString strTemp = str; 
char *pWord = strtok(strTemp.GetBuffer(0), ","); 
while (pWord != NULL) { 
    // Work 
    // .................. 
  
    afxDump << "\nWord:" << "\"" << pWord << "\"";  
    // Get Next Token 
    pWord = strtok( NULL, "," ); 
} 
strTemp.ReleaseBuffer();

donnera successivement :

Word:"aaa"
Word:"bbb"
Word:"ccc"
Word:"123"

et saute la valeur vide…

Code proposé pour fonctionner avec des CString :

Code C++ : Sélectionner tout
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
CString CStringTok(const char *szToken, const char *szDelimit, bool &rbEndParse) 
{ 
    CString strOrg, str; 
    static const char *pszOrg = NULL; 
  
    ASSERT(szDelimit != NULL); 
  
    if(szToken) { 
        pszOrg = szToken; 
        rbEndParse = false; 
    } 
    if(!pszOrg) { 
        rbEndParse = true; 
        return ""; 
    } 
  
    strOrg = pszOrg; 
    int nPos = strOrg.Find(szDelimit); 
    if(nPos != -1) { 
        str = strOrg.Left(nPos); 
        pszOrg += (nPos + strlen(szDelimit)); 
    } else { 
        str = strOrg; 
        pszOrg = NULL;       
    } 
    return str; 
}
Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
CString strOrg = "aaa,bbb,,ccc"; 
  
bool bEndParse; 
CString strWord = CStringTok(strOrg, ",", bEndParse); 
while (!bEndParse) { 
    // Work 
    // .................. 
    afxDump << "\nWord:" << "\"" << strWord << "\"";  
    // Get Next Token 
    strWord = CStringTok(NULL, ",", bEndParse); 
}

donnera successivement :

Word:"aaa"
Word:"bbb"
Word:""
Word:"ccc"

Mis à jour le 27 novembre 2005 farscape

Code C++ : Sélectionner tout
BSTR chaine = SysAllocString(L"Exemple de chaine");

On pourra utiliser SysStringLen pour faire une copie par exemple

Code C++ : Sélectionner tout
BSTR chaine2 = SysAllocStringLen(chaine, SysStringLen(chaine));

Pour créer une chaîne depuis un char *, on pourra se reporter à l'utilisation de la fonction décrite ici Comment convertir un BSTR en chaîne ordinaire et vice-versa ?

Code C++ : Sélectionner tout
1
2
3
char t1[] = "Exemple"; 
BSTR test1; 
ASCtoBSTR(t1, &test1);

Mis à jour le 20 mai 2006 nico-pyright(c)

Code C++ : Sélectionner tout
1
2
3
4
BSTR chaine1 = SysAllocString(L"Exemple "); 
BSTR chaine2 = SysAllocString(L"de chaine"); 
BSTR chaine3; 
VarBstrCat(chaine1, chaine2, &chaine3);

Mis à jour le 20 mai 2006 nico-pyright(c)

Il ne faudra pas oublier de libérer la mémoire avec SysFreeString

Code C++ : Sélectionner tout
SysFreeString(chaineBstr);

Mis à jour le 20 mai 2006 nico-pyright(c)

La classe CString dispose d'une méthode Format qui prend en charge les conversions des types entier, double, float ,long etc. de la même manière que la fonction printf ou sprintf du C,
Elle utilise donc les mêmes options.

Quelques exemples de conversions :

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
CString str; 
str.Format(_T("Float arrondi 2 décimales: %.2f\n"), 12345.12345); 
str.Format(_T("Float longueur 10 dont 2 décimales: %10.2f\n"), 12345.12345); 
str.Format(_T("entier cadré a gauche : %.6d\n"), 35); 
str.Format(_T("entier cadré avec zéro : %06d\n"), 35); 
CString str2=_T("essai") ; 
str.Format(_T("chaine :%s: \n"), static_cast<const char *>(str2)); 
char c='1'; 
str.Format(_T("char %c", c) ;

Pour plus de détails, consultez la liste des spécifications de format

Mis à jour le 22 janvier 2007 farscape

Code C++ : Sélectionner tout
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
{ 
        CStringW wstr = L"Chaine UNICODE"; 
        CStringA str(wstr);  // convertit en ANSI 
        LPCSTR lpcstr = str; 
        AfxMessageBox(lpcstr); 
    } 
    { 
        CComBSTR bstr = L"Chaine UNICODE"; 
        CStringA str(bstr); // convertit en ANSI 
        LPCSTR lpcstr = str; 
        AfxMessageBox(lpcstr); 
    } 
    { 
        CStringA str = "Chiane ANSI"; 
        CStringW wstr(str); // convertit en UNICODE 
        LPCWSTR lpcwstr = wstr; 
    } 
    { 
        CStringA str = "Chaine ANSI"; 
        CComBSTR bstr(str); // convertit en UNICODE 
        BSTR b = bstr; 
    } 
    { 
        GUID guid; 
        ::CoCreateGuid(&guid);  // j'obtient un GUID 
        CComBSTR bstrGuid(guid); // je convertit en UNICODE 
        CStringA strGuid(bstrGuid);  // Je convertit en ANSI 
        AfxMessageBox(strGuid);     // et j'affiche 
        AfxMessageBox(CStringA(CComBSTR(guid))); // ou bien... 
    }

Les constructeurs des classes CString et CComBSTR réalisent aisément des conversions pour nous.
Encore mieux CComBSTR convertit un GUID (Global Unique Identifier ou UUID= Universal Unique ID) en Unicode BSTR.

Mis à jour le 22 janvier 2007 Gabrielly

En dehors des méthodes déjà présentées pour la conversion Comment convertir une CString en int, double, long ?

Voici une autre méthode plus C++ de procéder :

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <string> 
#include <iostream> 
#include <sstream> 
  
template<typename T,typename S> 
bool FromString( const S & Str, T & Dest ) 
{ 
#ifdef _UNICODE 
    std::wistringstream iss( Str ); 
#else 
    std::istringstream iss( Str ); 
#endif 
    // tenter la conversion vers Dest 
    return iss >> Dest != 0; 
}

Utilisation :

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int nInt ; 
FromString(_T("10"), nInt ); // conversion en int. 
  
double dDouble; 
FromString( _T("3.14107"), dDouble ); // conversion en double 
  
CString str=_T("1200"); 
#ifdef _UNICODE 
    std::wstring strstl; 
#else 
    std::string strstl; 
#endif 
  
strstl=_T("1200"); 
int n=0; 
FromString(str.GetString(),n); 
n=0; 
FromString(strstl,n);

Mis à jour le 17 septembre 2007 farscape

les MFC comme l'api 32 permettent avec GetDlgItemInt la récupération du contenu d'un contrôle sous forme d'entier.
Mais quid des autres types long, float, double ?
Pour ces autres types il faudra attacher au contrôle une variable correspondante au type de donnée souhaité et appeler la méthode UpdateData(TRUE) pour disposer de la valeur.
Le code qui suit permet de se passer de l'association d'une variable à un contrôle et donc de récupérer directement la valeur pour le type souhaité.

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <sstream>  
#include <string>  
#include <iostream>  
  
template<typename T> 
bool FromCtrl( const CWnd & Ctrl, T & Dest ) 
{ 
    CString Str; 
    Ctrl.GetWindowText(Str); 
#ifdef _UNICODE 
    std::wistringstream iss( static_cast<LPCTSTR>( Str) ); 
#else 
	std::istringstream iss( static_cast<LPCTSTR>( Str) ); 
#endif 
    // tenter la conversion vers Dest 
    return iss >> Dest != 0; 
}

Utilisation :

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
double d; 
FromCtrl(*GetDlgItem(IDC_EDITNOM),d); 
if(d==10.0) 
{ 
    // traitement 
} 
// etc.

Mis à jour le 17 septembre 2007 farscape

Les MFC comme l'api 32 permettent avec SetDlgItemInt l'affection d'un entier au contrôle.
Mais quid des autres types long, float, double ?
Pour ces autres types il faudra attacher au contrôle une variable correspondante au type de donnée traité et appeler la méthode UpdateData(FALSE) pour mettre à jour le contrôle.
Le code qui suit permet de se passer de l'association d'une variable à un contrôle et donc d'affecter directement une valeur d'un type donné au contrôle.

Code C++ : Sélectionner tout
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
40
41
#include <sstream> 
#include <string> 
#include <iomanip> 
#include <iostream> 
  
class FormatNum 
{ 
public : 
    FormatNum(){} 
    template <typename T> 
    FormatNum(const T&t) 
    { 
        operator <<(t); 
    } 
    template <typename T> 
    FormatNum & operator << (const T& t) 
    {         
        m_ss << t; 
        return *this; 
    } 
  
public : 
#ifdef _UNICODE 
    std::wstringstream m_ss; 
#else 
    std::stringstream m_ss; 
#endif 
}; 
  
template<typename T> 
void ToCtrl(CWnd & Ctrl,const T & Src,FormatNum &rFormat=FormatNum()) 
{ 
    rFormat << Src; 
  
#ifdef _UNICODE 
    std::wstring s=rFormat.m_ss.str(); 
#else 
    std::string s=rFormat.m_ss.str(); 
#endif 
    Ctrl.SetWindowText(s.c_str()); 
}

Utilisation :

Code C++ : Sélectionner tout
1
2
3
4
5
// met 10.345 dans le contrôle. 
ToCtrl(*GetDlgItem(IDC_EDITNUM),10.345); 
// met 10.35 dans le contrôle. 
ToCtrl(*GetDlgItem(IDC_EDITNUM),10.345, 
            FormatNum()<<std::setprecision(4));

Le traitement se décompose en deux parties :
La fonction modèle ToCtrl permettant la transformation du type utilisateur et l'affectation de la chaîne au contrôle passée en argument.
Un objet fonction FormatNum optionnel qui permet le formatage du flux pour contrôler la conversion, l'enchainement des arguments, et qui fournit l'objet flux de conversion de la classe stringstream à la fonction modèle ToCtrl.

Voyons son utilisation dans les exemples qui suivent :
Dans le cas d'un double ou float si on veut maitriser la précision du nombre envoyé on pourra utiliser la fonction setprecision définie dans l'entête standard <iomanip> pour fixer le nombre de digits souhaités.
Vous pouvez bien-sûr utiliser les autres fonctions et compléter le flux

Exemples :
Contrôler la longueur de la chaîne créée, et spécifier un caractère de remplissage.
Code C++ : Sélectionner tout
1
2
3
// donne 0000010.35 
ToCtrl(*GetDlgItem(IDC_EDITNUM),10.345, 
       FormatNum()<<std::setprecision(4)<<std::setfill(_TCHAR('0'))<<std::setw(10));

Cet exemple impose une précision de 4 digits, une chaîne de 10 caractères remplie avec des '0'.
Dans le même ordre d'idée on pourra fixer la base de conversion...
Code C++ : Sélectionner tout
1
2
3
// donne 0000000020 
ToCtrl(*GetDlgItem(IDC_EDITNUM),32, 
    FormatNum()<<std::setprecision(4)<<std::setfill(_TCHAR('0'))<<std::setw(10)<<setbase(16));

Enfin rajouter du texte devant la conversion :
Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
// donne: Conversion Hexa: 0x0000000020 
ToCtrl(*GetDlgItem(IDC_EDITNUM), 
32, 
FormatNum()<<_T("Conversion Hexa: 0x") <<std::setprecision(4)<<std::setfill(_TCHAR('0'))<<std::setw(10)<<setbase(16)); 
//ou 
ToCtrl(*GetDlgItem(IDC_EDITNUM), 
32, 
FormatNum(_T("Conversion Hexa: 0x"))<<std::setprecision(4)<<std::setfill(_TCHAR('0'))<<std::setw(10)<<setbase(16));

Ou encore une syntaxe plus aérée :
Code C++ : Sélectionner tout
1
2
3
4
FormatNum format; 
format <<_T("Conversion Hexa: 0x") <<std::setprecision(4)<<std::setfill(_TCHAR('0'))<<std::setw(10)<<setbase(16); 
  
ToCtrl(*GetDlgItem(IDC_EDITNUM),32,format); // donne: Conversion Hexa: 0x0000000020[FONT=monospace]

Vous noterez aussi l'utilisation optionnelle de la spécification du format de conversion (FormatNum).
On pourra compléter notre traitement par une fonction de conversion vers une CString ou string de la STL.
Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
template<typename T,typename S> 
void ToString(S & rstr,const T & Src,FormatNum &rFormat=FormatNum()) 
{     
    rFormat << Src; 
#ifdef _UNICODE 
    std::wstring s=rFormat.m_ss.str(); 
#else 
    std::string s=rFormat.m_ss.str(); 
#endif 
    rstr=s.c_str(); 
}

Utilisation :
Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
CString str; 
ToString(str,1200); 
#ifdef _UNICODE 
    std::wstring strstl; 
#else 
    std::string strstl; 
#endif 
ToString(strstl,1200);

Mis à jour le 17 septembre 2007 farscape

UTF-8 (UCS transformation format 8 bits) permet de coder de l'Unicode sous une suite de 4 octets maximum.
Cette codification est par exemple utilisée dans le fichier document.xml au format OpenXml de Word 2007.
Les caractères dont le code ASCII est supérieur à 127 sont codés sur plusieurs octets.
Le code ci-dessus s'appuie sur la description donnée dans Wikipédia

Notes :

  • Une chaîne au format UTF8 peut être contenue dans une CString multi bytes.
  • J'ai implémenté la codification sur 4 octets mais l'exemple de Wikipédia avec le "?" ne semble pas correct dans ce cas puisque son code ASCII est égal à 63.
  • Ce code ne fonctionne pas directement avec Visual 6.0 à cause des CString: On ne dispose pas de CStringA et de CStringW...

Code C++ : Sélectionner tout
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
//------------------------------------------------------------------------- 
CStringA  UTF8EncodeString(const CStringA str) 
{ 
   CStringW input(str); 
   CStringA output; 
   for(int i=0; i < input.GetLength(); i++) 
   { 
      // 0xxxxxxx 
      if(input[i] < 0x80) 
      { 
        output+=input[i];          
      }        
      // C0          80     
      // 110xxxxx 10xxxxxx       
      else if((input[i] > 0x7F) && (input[i] < 0x800)) 
      { 
         output+=static_cast<unsigned char>(0xC0 | (input[i] >> 6)); 
         output+=static_cast<unsigned char>(0x80 | (input[i] & 0x3F));                       
      } 
      // E0       80       80 
      // 1110xxxx 10xxxxxx 10xxxxxx 
      else if(input[i] < 0x8000) 
      { 
        output+=static_cast<unsigned char>(0xE0 | (input[i] >> 12));          
        output+=static_cast<unsigned char>(0x80 | (input[i] >> 6 & 0x3F));          
        output+=static_cast<unsigned char>(0x80 | (input[i] & 0x3F)); 
      } 
      else 
      {  // F0      80       80       80 
         //11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
        output+=static_cast<unsigned char>(0xF0 | (input[i] >> 12)>>6); 
        output+=static_cast<unsigned char>(0x80 | (input[i] >> 12 & 0x3F)); 
        output+=static_cast<unsigned char>(0x80 | (input[i] >> 6 & 0x1F)); 
        output+=static_cast<unsigned char>(0x80 | (input[i] & 0x3F)); 
      } 
   } 
   return output; 
}
Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
CStringA input,output; 
input = "é"; 
output = UTF8EncodeString(input); 
TRACE("\n output é:%s", static_cast<const char *>(output)); 
  
input = "€"; 
output = UTF8EncodeString(input); 
TRACE("\n output €:%s",static_cast<const char *>(output));

Mis à jour le 7 juillet 2008 farscape

Pour plus d'informations voir la question  Comment encoder une chaîne au format UTF8 ?

Code C++ : Sélectionner tout
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
CStringA UTF8DecodeString(const CStringA input) 
{    
   CStringW output; 
   for(int i=0; i < input.GetLength();i++) 
   {   
      // F0      80       80       80 
      //11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
      if((input[i] & 0xFE) == 0xFE) 
      { 
           output+= static_cast<wchar_t>(((input[i] & 7 )<< 18) | ((input[i+1] & 0x3F) << 12) | ((input[i+2] & 0x3F) << 6) | (input[i+3] & 0x3F)); 
           i += 3; 
      } 
      else 
      // E0       80       80 
      // 1110xxxx 10xxxxxx 10xxxxxx 
      if((input[i] & 0xE0) == 0xE0) 
      { 
         output+= static_cast<wchar_t>(((input[i] & 0x0F) << 12) | ((input[i+1] & 0x3F) << 6) | (input[i+2] & 0x3F)); 
         i += 2; 
      } 
      // C0       80 
      // 110xxxxx 10xxxxxx 
      else if((input[i] & 0xC0) == 0xC0) 
      { 
         output+= static_cast<wchar_t>(((input[i] & 0x1F) << 6) | (input[i+1] & 0x3F)); 
         i ++; 
      } 
      // 0xxxxxxx 
      else if(input[i] < 0x80)   output+=input[i];            
   } 
   return CStringA(output); 
}
Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
CStringA input,output; 
input = "é"; 
output = UTF8EncodeString(input); 
TRACE("\n output é:%s",static_cast<const char *>(output)); 
output = UTF8DecodeString(output); 
TRACE("\n output é:%s",static_cast<const char *>(output)); 
  
input = "€"; 
output = UTF8EncodeString(input); 
TRACE("\n output €:%s",static_cast<const char *>(output)); 
output = UTF8DecodeString(output); 
TRACE("\n output é:%s",static_cast<const char *>(output));

Mis à jour le 7 juillet 2008 farscape

La conversion d'une chaîne UNICODE en chaîne de caractères est relativement aisée avec les MFC récentes (après visual 6.0).
En effet la classe CString permet de travailler sur les deux conventions UNICODE et Multi-Byte dans un même projet.
On aura alors :
La classe CString qui suivra le paramétrage du projet : UNICODE ou Multi-Byte
La classe CStringA pour travailler avec des chaînes de caractères Multi-Byte (char *) .
La classe CStringW pour travailler avec des chaînes Unicode.
Une conversion d'une chaîne UNICODE en Multi-Byte devient une chose aisée :

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
// réglage du projet en UNICODE 
CString strWide = _T("chaine de caractères"); 
CStringA strA(strWide); 
  
CString strWideDup(strA); // l'inverse 
VERIFY(strWideDup == strWide); 
  
char *sz = strA.GetBuffer(0);

L'exemple ci-dessus part d'une CString UNICODE et fournit une CString Multi-Byte et un pointeur sur char *.
Et enfin fabrique une CString UNICODE à partir d'une CString Multi-Byte

Avec Visual 6.0 :
CString travaille dans le mode réglé dans le projet.
Pour transformer une CString Unicode en chaîne de caractères il faudra utiliser l'api WideCharToMultiByte :

Code C++ : Sélectionner tout
1
2
3
4
5
6
// réglage du projet en UNICODE 
CString strWide = _T("chaine de caractères"); 
char *sz = new char [strWide.GetLength()+1] ; 
WideCharToMultiByte(CP_ACP, 0, strWide, -1, sz, strWide.GetLength()+1, NULL, NULL ); 
//...... 
delete[] sz;

Pour transformer une chaîne de caractères en chaîne Unicode on utilisera MultiByteToWideChar

Code C++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// réglage du projet en UNICODE 
CString strWide = _T("chaine de caractères"); 
char *sz = new char [strWide.GetLength()+1] ; 
WideCharToMultiByte( CP_ACP, 0, strWide, -1, sz, strWide.GetLength()+1, NULL, NULL ); 
  
int nSize = strlen(sz) + 1; 
TCHAR *wsz = new TCHAR[nSize]; 
MultiByteToWideChar(CP_ACP, 0, sz,nSize, wsz,nSize); 
CString strWideDup = wsz; 
  
VERIFY(strWideDup == strWide); 
//...... 
delete[] wsz; 
delete[] sz;

Mis à jour le 7 juillet 2008 farscape

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2022 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.