Domanda

CString è abbastanza utile, mentre std :: string è più compatibile con il contenitore STL. Sto usando hash_map . Tuttavia, hash_map non supporta CString come chiave, quindi desidero convertire CString in std :: string .

Scrivere una funzione hash CString sembra richiedere molto tempo.

CString -----> std::string

Come posso farlo?

std::string -----> CString:

inline CString toCString(std::string const& str)
{
    return CString(str.c_str()); 
}

Ho ragione?


Modifica

Ecco altre domande:

Come posso convertire wstring , CString l'uno nell'altro?

//wstring -> CString,
std::wstring src;
CString result(src.c_str());
//CString->wstring. 
CString src;
::std::wstring des(src.GetString());

C'è qualche problema ?

Come posso convertire std :: wstring , std :: string l'uno nell'altro?

È stato utile?

Soluzione

Secondo CodeGuru :

Da

CString a std :: string :

CString cs("Hello");
std::string s((LPCTSTR)cs);

MA: std :: string non può sempre essere costruito da un LPCTSTR . cioè il codice fallirà per le build UNICODE.

Dato che std :: string può essere costruito solo da LPSTR / LPCSTR , un programmatore che utilizza VC ++ 7.xo meglio può utilizzare la conversione classi come CT2CA come intermediario.

CString cs ("Hello");
// Convert a TCHAR string to a LPCSTR
CT2CA pszConvertedAnsiString (cs);
// construct a std::string using the LPCSTR input
std::string strStd (pszConvertedAnsiString);

std :: string a CString : (Da Domande frequenti su CString di Visual Studio ... )

std::string s("Hello");
CString cs(s.c_str());

CStringT può costruire sia da stringhe di caratteri sia da caratteri di grandi dimensioni. cioè Può convertire da char * (cioè LPSTR ) o da wchar_t * ( LPWSTR ).

In altre parole, specializzazione dei caratteri (di CStringT ) ovvero CStringA , wchar_t -specilization CStringW , e TCHAR -specialization CString può essere costruito da char o da caratteri ampi, null terminato (la terminazione null è molto importante qui ) origini stringa.
Althoug IInspectable modifica la "null-termination" parte nei commenti :

  

Non è richiesta la terminazione NUL .
   CStringT ha costruttori di conversione che accettano un argomento di lunghezza esplicita. Questo significa anche che puoi costruire oggetti CStringT partendo da std :: string con caratteri NUL incorporati.

Altri suggerimenti

Risolvilo usando std :: basic_string < TCHAR > invece di std :: string e dovrebbe funzionare bene indipendentemente dall'impostazione del carattere.

È più efficace convertire CString in std :: string usando la conversione in cui è specificata la lunghezza.

CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());

In stretto circuito, questo migliora notevolmente le prestazioni.

Se vuoi qualcosa di più simile al C ++, questo è quello che uso. Anche se dipende da Boost, questo è solo per le eccezioni. Puoi rimuovere facilmente quelli che lo fanno dipendere solo dall'STL e dalla WideCharToMultiByte () API Win32.

#include <string>
#include <vector>
#include <cassert>
#include <exception>

#include <boost/system/system_error.hpp>
#include <boost/integer_traits.hpp>

/**
 * Convert a Windows wide string to a UTF-8 (multi-byte) string.
 */
std::string WideStringToUtf8String(const std::wstring& wide)
{
    if (wide.size() > boost::integer_traits<int>::const_max)
        throw std::length_error(
            "Wide string cannot be more than INT_MAX characters long.");
    if (wide.size() == 0)
        return "";

    // Calculate necessary buffer size
    int len = ::WideCharToMultiByte(
        CP_UTF8, 0, wide.c_str(), static_cast<int>(wide.size()), 
        NULL, 0, NULL, NULL);

    // Perform actual conversion
    if (len > 0)
    {
        std::vector<char> buffer(len);
        len = ::WideCharToMultiByte(
            CP_UTF8, 0, wide.c_str(), static_cast<int>(wide.size()),
            &buffer[0], static_cast<int>(buffer.size()), NULL, NULL);
        if (len > 0)
        {
            assert(len == static_cast<int>(buffer.size()));
            return std::string(&buffer[0], buffer.size());
        }
    }

    throw boost::system::system_error(
        ::GetLastError(), boost::system::system_category);
}

(da VS2012 ... e almeno fino a VS2017 v15.8.1)

Dal momento che è un progetto MFC & amp; CString è una classe MFC, MS fornisce una nota tecnica TN059: utilizzo di MFC MBCS / Unicode Macro di conversione e Macro di conversione generica:

A2CW      (LPCSTR)  -> (LPCWSTR)  
A2W       (LPCSTR)  -> (LPWSTR)  
W2CA      (LPCWSTR) -> (LPCSTR)  
W2A       (LPCWSTR) -> (LPSTR)  

Usa:

void Example() // ** UNICODE case **
{
    USES_CONVERSION; // (1)

    // CString to std::string / std::wstring
    CString strMfc{ "Test" }; // strMfc = L"Test"
    std::string strStd = W2A(strMfc); // ** Conversion Macro: strStd = "Test" **
    std::wstring wstrStd = strMfc.GetString(); // wsrStd = L"Test"

    // std::string to CString / std::wstring
    strStd = "Test 2";
    strMfc = strStd.c_str(); // strMfc = L"Test 2"
    wstrStd = A2W(strStd.c_str()); // ** Conversion Macro: wstrStd = L"Test 2" **

    // std::wstring to CString / std::string 
    wstrStd = L"Test 3";
    strMfc = wstrStd.c_str(); // strMfc = L"Test 3"
    strStd = W2A(wstrStd.c_str()); // ** Conversion Macro: strStd = "Test 3" **
}

-

Note:

(1) Affinché le macro di conversione abbiano spazio per memorizzare la lunghezza temporanea, è necessario dichiarare una variabile locale chiamata _convert che fa questo in ogni funzione che utilizza la conversione macro. Questo viene fatto invocando la macro USES_CONVERSION . Nel codice MFC VS2017 (atlconv.h) è simile al seguente:

#ifndef _DEBUG
    #define USES_CONVERSION int _convert; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw; (_lpw); LPCSTR _lpa; (_lpa)
#else
    #define USES_CONVERSION int _convert = 0; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw = NULL; (_lpw); LPCSTR _lpa = NULL; (_lpa)
#endif

Questo è un seguito alla risposta di Sal, in cui ha fornito la soluzione:

CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());

Ciò è utile anche quando si converte una C-String non tipica in uno std :: string

Un caso d'uso per me stava avendo un array di caratteri pre-allocato (come C-String), ma non è NUL terminato. (ovvero digest SHA). La sintassi di cui sopra mi consente di specificare la lunghezza del digest SHA dell'array char in modo che std :: string non debba cercare il carattere NUL terminante, che potrebbe essere presente o meno.

Ad esempio:

unsigned char hashResult[SHA_DIGEST_LENGTH];    
auto value = std::string(reinterpret_cast<char*>hashResult, SHA_DIGEST_LENGTH);

Funziona bene:

//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
    return CT2A(cst.GetString());
}

da questo post (grazie Mark Ransom )

Converti CString in stringa (VC6)

Ho provato questo e funziona benissimo.

std::string Utils::CString2String(const CString& cString) 
{
    std::string strStd;

    for (int i = 0;  i < cString.GetLength();  ++i)
    {
        if (cString[i] <= 0x7f)
            strStd.append(1, static_cast<char>(cString[i]));
        else
            strStd.append(1, '?');
    }

    return strStd;
}

Funziona per me:

std::wstring CStringToWString(const CString& s)
{
    std::string s2;
    s2 = std::string((LPCTSTR)s);
    return std::wstring(s2.begin(),s2.end());
}

CString WStringToCString(std::wstring s)
{
    std::string s2;
    s2 = std::string(s.begin(),s.end());
    return s2.c_str();
}

Tutte le altre risposte non rispondevano esattamente a ciò che stavo cercando, ovvero convertire al volo CString anziché archiviare il risultato in una variabile.

La soluzione è simile alla precedente ma è necessaria un'ulteriore fase per creare un'istanza di un oggetto senza nome. Sto illustrando con un esempio. Ecco la mia funzione che richiede std :: string ma ho CString .

void CStringsPlayDlg::writeLog(const std::string &text)
{
    std::string filename = "c:\\test\\test.txt";

    std::ofstream log_file(filename.c_str(), std::ios_base::out | std::ios_base::app);

    log_file << text << std::endl;
}

Come chiamarlo quando hai un CString ?

std::string firstName = "First";
CString lastName = _T("Last");

writeLog( firstName + ", " + std::string( CT2A( lastName ) ) );     

Nota che l'ultima riga non è un typecast diretto ma stiamo creando un oggetto std :: string senza nome e forniamo CString tramite il suo costruttore.

  

C'è qualche problema ?

Esistono diversi problemi:

  • CString è una specializzazione di modello di CStringT . A seconda del BaseType che descrive il tipo di carattere, esistono due specializzazioni concrete: CStringA (usando char ) e CStringW (utilizzando wchar_t ).
  • Mentre wchar_t su Windows è ubiquitariamente utilizzato per memorizzare unità di codice codificate UTF-16, l'utilizzo di char è ambiguo. Quest'ultimo memorizza comunemente caratteri codificati ANSI, ma può anche memorizzare dati ASCII, UTF-8 o persino binari.
  • Non conosciamo la codifica dei caratteri (o addirittura il tipo di carattere) di CString (che è controllata tramite il simbolo del preprocessore _UNICODE ), rendendo la domanda ambigua. Inoltre non conosciamo la codifica dei caratteri desiderata di std :: string .
  • La conversione tra Unicode e ANSI comporta una perdita intrinseca: la codifica ANSI può rappresentare solo un sottoinsieme del set di caratteri Unicode.

Per risolvere questi problemi, suppongo che wchar_t memorizzerà le unità di codice codificate UTF-16 e char conterrà sequenze di ottetti UTF-8. Questa è l'unica scelta ragionevole che puoi fare per garantire che le stringhe di origine e di destinazione conservino le stesse informazioni, senza limitare la soluzione a un sottoinsieme dei domini di origine o di destinazione.

Le seguenti implementazioni convertono tra CStringA / CStringW e std :: wstring / std :: string da UTF-8 a UTF-16 e viceversa:

#include <string>
#include <atlconv.h>

std::string to_utf8(CStringW const& src_utf16)
{
    return { CW2A(src_utf16.GetString(), CP_UTF8).m_psz };
}

std::wstring to_utf16(CStringA const& src_utf8)
{
    return { CA2W(src_utf8.GetString(), CP_UTF8).m_psz };
}

Le restanti due funzioni costruiscono oggetti stringa C ++ dalle stringhe MFC, lasciando invariata la codifica. Si noti che mentre le funzioni precedenti non sono in grado di far fronte ai caratteri NUL incorporati, queste funzioni sono immuni a questo.

#include <string>
#include <atlconv.h>

std::string to_std_string(CStringA const& src)
{
    return { src.GetString(), src.GetString() + src.GetLength() };
}

std::wstring to_std_wstring(CStringW const& src)
{
    return { src.GetString(), src.GetString() + src.GetLength() };
}

Puoi utilizzare CT2CA

CString datasetPath;
CT2CA st(datasetPath);
string dataset(st);

Se stai cercando di convertire facilmente tra altri tipi di stringhe, forse _bstr_t sarebbe più appropriata? Supporta la conversazione tra char , wchar_t e BSTR .

Un approccio interessante è quello di lanciare CString in CStringA all'interno di un costruttore string . A differenza di std :: string s ((LPCTSTR) cs); funzionerà anche se _UNICODE è definito. Tuttavia, in tal caso, questo eseguirà la conversione da Unicode a ANSI, quindi non è sicuro per valori Unicode più alti oltre il set di caratteri ASCII. Tale conversione è soggetta alla definizione del preprocessore _CSTRING_DISABLE_NARROW_WIDE_CONVERSION . https://msdn.microsoft.com/en-us/library/5bzxfsea. aspx

        CString s1("SomeString");
        string s2((CStringA)s1);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top