¿Cómo convertir CString y :: std :: string :: std :: wstring entre sí?

CString es bastante útil, mientras que std::string es más compatible con el contenedor STL. Estoy usando hash_map . Sin embargo, hash_map no admite CString como clave, por lo que quiero convertir CString en std::string .

Escribir una función hash de CString parece tomar mucho tiempo.

 CString -----> std::string 

¿Cómo puedo hacer esto?

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

¿Estoy en lo cierto?


EDITAR:

Aquí hay más preguntas:

¿Cómo puedo convertir wstring , CString entre ellos?

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

Hay algun problema?

¿Cómo puedo convertir std::wstring , std::string entre sí?

De acuerdo con CodeGuru :

CString a std::string :

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

PERO: std::string no siempre se puede construir desde un LPCTSTR . es decir, el código fallará para las construcciones UNICODE.

Como std::string solo puede construir desde LPSTR / LPCSTR , un progtwigdor que usa VC ++ 7.xo mejor puede utilizar clases de conversión como CT2CA como 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 to CString : (De las preguntas frecuentes de CString de Visual Studio … )

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

CStringT puede construir tanto de cadenas de caracteres como de caracteres anchos. es decir, puede convertir de char* (es decir, LPSTR ) o de wchar_t* ( LPWSTR ).

En otras palabras, la especialización de caracteres (de CStringT ), es decir, CStringA , wchar_t -specilization CStringW y TCHAR -specialization CString se pueden construir a partir de caracteres char o de caracteres amplios, nulo terminado (la terminación nula es muy importante aquí) fonts de cuerda
Althoug IInspectable modifica la parte de “terminación nula” en los comentarios :

NUL-terminación no es necesario .
CStringT tiene constructores de conversión que toman un argumento de longitud explícita. Esto también significa que puede construir objetos CStringT desde objetos std::string con caracteres NUL incrustados.

Resuelva eso usando std::basic_string lugar de std::string y debería funcionar bien independientemente de la configuración de su carácter.

Es más eficiente convertir CString a std::string usando la conversión donde se especifica la longitud.

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

En lazo cerrado, esto mejora significativamente el rendimiento.

Si quieres algo más similar a C ++, esto es lo que uso. Aunque depende de Boost, eso es solo por excepciones. Puede eliminar fácilmente aquellos que lo dejen para que dependan solo de la llamada a la API Win32 WideCharToMultiByte() STL.

 #include  #include  #include  #include  #include  #include  /** * 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::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(wide.size()), NULL, 0, NULL, NULL); // Perform actual conversion if (len > 0) { std::vector buffer(len); len = ::WideCharToMultiByte( CP_UTF8, 0, wide.c_str(), static_cast(wide.size()), &buffer[0], static_cast(buffer.size()), NULL, NULL); if (len > 0) { assert(len == static_cast(buffer.size())); return std::string(&buffer[0], buffer.size()); } } throw boost::system::system_error( ::GetLastError(), boost::system::system_category); } 

Este es un seguimiento de la respuesta de Sal, donde proporcionó la solución:

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

Esto también es útil al convertir un C-String no típico a std :: string

Un caso de uso para mí era tener una matriz de caracteres preasignada (como C-String), pero no está terminada en NUL. (es decir, resumen de SHA). La syntax anterior me permite especificar la longitud del resumen SHA de la matriz char para que std :: string no tenga que buscar el carácter terminante NUL, que puede estar o no allí.

Como:

 unsigned char hashResult[SHA_DIGEST_LENGTH]; auto value = std::string(reinterpret_casthashResult, SHA_DIGEST_LENGTH); 

Esto funciona bien:

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

de esta publicación (Gracias Mark Ransom )

Convierta CString en cadena (VC6)

Lo he probado y funciona bien.

 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(cString[i])); else strStd.append(1, '?'); } return strStd; } 

(Desde VS2012 … y al menos hasta VS2017 v15.8.1)

Dado que es un proyecto de MFC y CString es una clase de MFC, MS proporciona una Nota técnica TN059: Uso de macros de conversión de MFC MBCS / Unicode y macros de conversión genérica:

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

Utilizar:

 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" ** } 

Notas al pie:

(1) Para que las macros de conversión tengan espacio para almacenar la longitud temporal, es necesario declarar una variable local llamada _convert que hace esto en cada función que usa las macros de conversión. Esto se hace invocando la macro USES_CONVERSION . En el código VS2017 MFC (atlconv.h) se ve así:

 #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 

Funciona para mi:

 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(); } 

Todas las demás respuestas no respondieron exactamente a lo que estaba buscando, que consistía en convertir CString sobre la marcha en lugar de almacenar el resultado en una variable.

La solución es similar a la anterior, pero necesitamos un paso más para crear un objeto sin nombre. Estoy ilustrando con un ejemplo. Aquí está mi función que necesita std::string pero tengo 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; } 

¿Cómo llamarlo cuando tienes un CString ?

 std::string firstName = "First"; CString lastName = _T("Last"); writeLog( firstName + ", " + std::string( CT2A( lastName ) ) ); 

Tenga en cuenta que la última línea no es un encasillado directo, pero estamos creando un objeto std::string sin nombre y suministramos el CString través de su constructor.

Hay algun problema?

Hay varios problemas:

  • CString es una especialización de plantilla de CStringT . Dependiendo de BaseType que describa el tipo de carácter, hay dos especializaciones concretas: CStringA (usando char ) y CStringW (usando wchar_t ).
  • Mientras que wchar_t en Windows se usa de forma ubicua para almacenar unidades de código codificadas en UTF-16, el uso de caracteres es ambiguo. Este último comúnmente almacena caracteres codificados ANSI, pero también puede almacenar datos ASCII, UTF-8 o incluso binarios.
  • No conocemos la encoding de caracteres (o incluso el tipo de carácter) de CString (que se controla a través del símbolo preprocesador _UNICODE ), por lo que la pregunta es ambigua. Tampoco sabemos la encoding de caracteres deseada de std::string .
  • La conversión entre Unicode y ANSI es inherentemente con pérdida: la encoding ANSI solo puede representar un subconjunto del juego de caracteres Unicode.

Para abordar estos problemas, supongo que wchar_t almacenará unidades de código codificadas en UTF-16, y char contendrá secuencias de octetos UTF-8. Esa es la única opción razonable que puede hacer para garantizar que las cadenas de origen y de destino retienen la misma información, sin limitar la solución a un subconjunto de los dominios de origen o de destino.

Las siguientes implementaciones convierten entre CStringA / CStringW y std::wstring / std::string mapping de UTF-8 a UTF-16 y viceversa:

 #include  #include  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 }; } 

Las dos funciones restantes construyen objetos de cadenas C ++ a partir de cadenas MFC, sin modificar la encoding. Tenga en cuenta que, si bien las funciones anteriores no pueden hacer frente a los caracteres incrustados NUL, estas funciones son inmunes a eso.

 #include  #include  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() }; } 

Si está buscando convertir fácilmente entre otros tipos de cadenas, ¿tal vez la clase _bstr_t sería más apropiada? Es compatible con la conversación entre char , wchar_t y BSTR .

Un enfoque interesante es convertir CString en CStringA dentro de un constructor de string . A diferencia de std::string s((LPCTSTR)cs); esto funcionará incluso si se define _UNICODE . Sin embargo, si ese es el caso, esto llevará a cabo la conversión de Unicode a ANSI, por lo que no es seguro para valores Unicode más altos más allá del conjunto de caracteres ASCII. Dicha conversión está sujeta a la definición del preprocesador _CSTRING_DISABLE_NARROW_WIDE_CONVERSION . https://msdn.microsoft.com/en-us/library/5bzxfsea.aspx

  CString s1("SomeString"); string s2((CStringA)s1);