Как конвертировать CString и :: std :: string :: std :: wstring друг в друга? - PullRequest
66 голосов
/ 03 ноября 2008

CString довольно удобен, а std::string более совместим с контейнером STL. Я использую hash_map. Однако hash_map не поддерживает CString в качестве ключа, поэтому я хочу преобразовать CString в std::string.

Запись хэш-функции CString, похоже, занимает много времени.

CString -----> std::string

Как я могу это сделать?

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

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

Я прав?


EDIT:

Вот еще вопросы:

Как я могу преобразовать wstring, CString друг в друга?

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

Есть ли какая-либо проблема?

Как я могу конвертировать std::wstring, std::string друг в друга?

Ответы [ 14 ]

85 голосов
/ 03 ноября 2008

Согласно CodeGuru :

CString до std::string:

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

НО: std::string не всегда можно построить из LPCTSTR. то есть код не удастся для сборок UNICODE.

Поскольку std::string может создавать только из LPSTR / LPCSTR, программист, использующий VC ++ 7.x или выше, может использовать классы преобразования, такие как CT2CA, в качестве посредника.

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 до CString: (с Часто задаваемые вопросы по Visual Studio для CString ... )

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

CStringT может составлять как строки символов, так и строки широких символов. то есть он может конвертировать из char* (т.е. LPSTR) или из wchar_t* (LPWSTR).

Другими словами, специализация char (из CStringT), т. Е. CStringA, wchar_t -специализация CStringW и TCHAR -специализация CString, может быть построена из char или широкого символ, нулевое окончание (здесь очень важно нулевое окончание) строковые источники.
Althoug IInspectable исправляет часть "нулевого завершения" в комментариях :

NUL-завершение не требуется .
CStringT имеет конструкторы преобразования, которые принимают явный аргумент длины. Это также означает, что вы можете создавать CStringT объекты из std::string объектов со встроенными NUL символами.

34 голосов
/ 03 ноября 2008

Решите это, используя std::basic_string<TCHAR> вместо std::string, и оно должно работать нормально независимо от настроек вашего персонажа.

5 голосов
/ 03 июня 2011

Более эффективно преобразовать CString в std::string, используя преобразование, в котором указана длина.

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

В узком цикле это значительно повышает производительность.

4 голосов
/ 12 июля 2009

Если вы хотите что-то более C ++ - например, это то, что я использую. Хотя это зависит от Boost, это только для исключений. Вы можете легко удалить тех из них, которые зависят от STL и WideCharToMultiByte() Win32 API.

#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);
}
2 голосов
/ 21 августа 2018

(с VS2012 ... и, по крайней мере, до VS2017 v15.8.1)

Поскольку это проект MFC, а CString - класс MFC, MS предоставляет Техническое примечание TN059: Использование макросов преобразования MFC / Unicode MFC и универсальных макросов преобразования:

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

Использование:

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

-

Примечания:

(1) Чтобы в макросах преобразования было место для хранения временной длины, необходимо объявить локальную переменную с именем _convert, которая делает это в каждой функции, использующей макросы преобразования. Это делается путем вызова макроса USES_CONVERSION. В коде MFC VS2017 (atlconv.h) это выглядит так:

#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
1 голос
/ 21 августа 2018

из этого поста (спасибо Марк Рэнсом )

Преобразовать CString в строку (VC6)

Я проверил это, и он отлично работает.

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;
}
1 голос
/ 22 января 2017

Это прекрасно работает:

//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
    return CT2A(cst.GetString());
}
1 голос
/ 10 марта 2016

Это продолжение ответа Сэла, где он / она предоставил решение:

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

Это полезно также при преобразовании нестандартной C-строки в std :: string

Вариант использования для меня имел предварительно выделенный массив символов (например, C-String), но он не завершен NUL. (т. е. дайджест SHA). Приведенный выше синтаксис позволяет мне указать длину дайджеста SHA массива char, так что std :: string не нужно искать завершающий символ NUL, который может быть или не быть там.

Например:

unsigned char hashResult[SHA_DIGEST_LENGTH];    
auto value = std::string(reinterpret_cast<char*>hashResult, SHA_DIGEST_LENGTH);
0 голосов
/ 19 апреля 2019

Вы можете использовать CT2CA

CString datasetPath;
CT2CA st(datasetPath);
string dataset(st);
0 голосов
/ 06 сентября 2018

Есть ли какая-либо проблема?

Есть несколько проблем:

  • CString - это шаблонная специализация CStringT . В зависимости от BaseType , описывающего тип символа, существует две конкретные специализации: CStringA (с использованием char) и CStringW (с использованием wchar_t).
  • Хотя wchar_t в Windows повсеместно используется для хранения кодированных единиц UTF-16, использование char неоднозначно. Последний обычно хранит символы в кодировке ANSI, но также может хранить ASCII, UTF-8 или даже двоичные данные.
  • Мы не знаем кодировку символов (или даже тип символов) CString (которая управляется с помощью символа препроцессора _UNICODE), что делает вопрос неоднозначным. Мы также не знаем желаемую кодировку символов std::string.
  • Преобразование между Юникодом и ANSI по своей природе сопряжено с потерями: кодировка ANSI может представлять только подмножество набора символов Юникода.

Для решения этих проблем я собираюсь предположить, что wchar_t будет хранить кодированные единицы UTF-16, а char будет содержать октетные последовательности UTF-8. Это единственный разумный выбор, который вы можете сделать, чтобы гарантировать, что строки источника и назначения сохраняют одну и ту же информацию, не ограничивая решение подмножеством доменов источника или назначения.

Следующие реализации преобразуют между CStringA / CStringW и std::wstring / std::string отображением из UTF-8 в UTF-16 и наоборот:

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

Оставшиеся две функции создают строковые объекты C ++ из строк MFC, оставляя кодировку без изменений. Обратите внимание, что хотя предыдущие функции не могут работать со встроенными символами NUL, эти функции защищены от этого.

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