C++ 如何将 CString 和 ::std::string ::std::wstring 相互转换?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/258050/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:06:29  来源:igfitidea点击:

How to convert CString and ::std::string ::std::wstring to each other?

c++mfccstringstdstring

提问by user25749

CStringis quite handy, while std::stringis more compatible with STL container. I am using hash_map. However, hash_mapdoes not support CStringas key, so I want to convert CStringinto std::string.

CString非常方便,同时std::string更兼容STL容器。我正在使用hash_map. 但是,hash_map不支持CString作为键,所以我想转换CStringstd::string.

Writing a CStringhash function seems to take a lot of time.

编写CString散列函数似乎需要很多时间。

CString -----> std::string

How can I do this?

我怎样才能做到这一点?

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

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

Am I right?

我对吗?



EDIT:

编辑:

Here are more questions:

这里有更多问题:

How can I convert wstring, CStringto each other?

我怎么能转换wstringCString彼此?

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

Is there anyproblem?

什么问题吗?

How can I convert std::wstring, std::stringto each other?

我怎么能转换std::wstringstd::string彼此?

回答by VonC

According to CodeGuru:

根据CodeGuru 的说法

CStringto std::string:

CStringstd::string

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

BUT:std::stringcannot always construct from a LPCTSTR. i.e. the code will fail for UNICODE builds.

但是:std::string不能总是从LPCTSTR. 即代码将失败用于 UNICODE 构建。

As std::stringcan construct only from LPSTR/ LPCSTR, a programmer who uses VC++ 7.x or better can utilize conversion classes such as CT2CAas an intermediary.

由于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::stringto CString: (From Visual Studio's CString FAQs...)

std::stringCString:(来自Visual Studio 的 CString 常见问题解答...

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

CStringTcan construct from both character or wide-character strings. i.e. It can convert from char*(i.e. LPSTR) or from wchar_t*(LPWSTR).

CStringT可以从字符或宽字符串构造。即它可以从char*(ie LPSTR) 或从wchar_t*( LPWSTR) 转换。

In other words, char-specialization (of CStringT) i.e. CStringA, wchar_t-specilization CStringW, and TCHAR-specialization CStringcan be constructed from either charor wide-character, null terminated (null-termination is very important here)string sources.
Althoug IInspectableamends the "null-termination" part in the comments:

换句话说, char-specialization (of CStringT) 即CStringAwchar_t-specilizationCStringWTCHAR-specializationCString可以从任一char或宽字符构造,空终止(空终止在这里非常重要)字符串源。
Althoug IInspectable修订了“空终止”部分中的评论

NUL-termination is not required.
CStringThas conversion constructors that take an explicit length argument. This also means that you can construct CStringTobjects from std::stringobjects with embedded NULcharacters.

不需要 NUL 终止
CStringT具有采用显式长度参数的转换构造函数。这也意味着您可以CStringTstd::string带有嵌入NUL字符的对象构造对象。

回答by OJ.

Solve that by using std::basic_string<TCHAR>instead of std::stringand it should work fine regardless of your character setting.

通过使用std::basic_string<TCHAR>代替来解决这个问题,std::string无论您的字符设置如何,它都应该可以正常工作。

回答by Sal

It is more effecient to convert CStringto std::stringusing the conversion where the length is specified.

转换CStringstd::string使用指定长度的转换更有效。

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

In tight loop this makes a significant performance improvement.

在紧密循环中,这会显着提高性能。

回答by thehouse

If you want something more C++-like, this is what I use. Although it depends on Boost, that's just for exceptions. You can easily remove those leaving it to depend only on the STL and the WideCharToMultiByte()Win32 API call.

如果你想要更像 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);
}

回答by Amit G.

(Since VS2012 ...and at least until VS2017 v15.8.1)

(从 VS2012 开始……至少到 VS2017 v15.8.1)

Since it's a MFC project & CString is a MFC class, MS provides a Technical Note TN059: Using MFC MBCS/Unicode Conversion Macrosand Generic Conversion Macros:

由于它是一个 MFC 项目且 CString 是一个 MFC 类,因此 MS 提供了技术说明TN059:使用 MFC MBCS/Unicode 转换宏和通用转换宏:

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

Use:

用:

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

--

——

Footnotes:

脚注:

(1) In order to for the conversion-macros to have space to store the temporary length, it is necessary to declare a local variable called _convertthat does this in each function that uses the conversion macros. This is done by invoking the USES_CONVERSIONmacro. In VS2017 MFC code (atlconv.h) it looks like this:

(1) 为了让转换宏有空间来存储临时长度,有必要_convert在每个使用转换宏的函数中声明一个调用的局部变量。这是通过调用USES_CONVERSION宏来完成的。在 VS2017 MFC 代码(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

回答by IInspectable

Is there anyproblem?

什么问题吗?

There are several issues:

有几个问题:

  • CStringis a template specialization of CStringT. Depending on the BaseTypedescribing the character type, there are two concrete specializations: CStringA(using char) and CStringW(using wchar_t).
  • While wchar_ton Windows is ubiquitously used to store UTF-16 encoded code units, using charis ambiguous. The latter commonly stores ANSI encoded characters, but can also store ASCII, UTF-8, or even binary data.
  • We don't know the character encoding (or even character type) of CString(which is controlled through the _UNICODEpreprocessor symbol), making the question ambiguous. We also don't know the desired character encoding of std::string.
  • Converting between Unicode and ANSI is inherently lossy: ANSI encoding can only represent a subset of the Unicode character set.
  • CStringCStringT的模板特化。根据描述字符类型的BaseType,有两个具体的特化:CStringA(using char) 和CStringW(using wchar_t)。
  • 虽然wchar_t在 Windows 上普遍用于存储 UTF-16 编码的代码单元,但使用char是不明确的。后者通常存储 ANSI 编码的字符,但也可以存储 ASCII、UTF-8 甚至二进制数据。
  • 我们不知道(CString通过_UNICODE预处理器符号控制)的字符编码(甚至字符类型),使问题变得模棱两可。我们也不知道std::string.
  • 在 Unicode 和 ANSI 之间转换本质上是有损的:ANSI 编码只能表示 Unicode 字符集的一个子集。

To address these issues, I'm going to assume that wchar_twill store UTF-16 encoded code units, and charwill hold UTF-8 octet sequences. That's the only reasonable choice you can make to ensure that source and destination strings retain the same information, without limiting the solution to a subset of the source or destination domains.

为了解决这些问题,我将假设wchar_t它将存储 UTF-16 编码的代码单元,char并将保存 UTF-8 八位字节序列。这是您可以做出的唯一合理选择,以确保源字符串和目标字符串保留相同的信息,而不会将解决方案限制为源域或目标域的子集。

The following implementations convert between CStringA/CStringWand std::wstring/std::stringmapping from UTF-8 to UTF-16 and vice versa:

以下实现将CStringA/CStringWstd::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 };
}

The remaining two functions construct C++ string objects from MFC strings, leaving the encoding unchanged. Note that while the previous functions cannot cope with embedded NUL characters, these functions are immune to that.

其余两个函数从 MFC 字符串构造 C++ 字符串对象,保持编码不变。请注意,虽然之前的函数无法处理嵌入的 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() };
}

回答by Pat. ANDRIA

from this post (Thank you Mark Ransom)

来自这篇文章(谢谢Mark Ransom

Convert CString to string (VC6)

将 CString 转换为字符串 (VC6)

I have tested this and it works fine.

我已经测试过了,它工作正常。

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

回答by Neil

This is a follow up to Sal's answer, where he/she provided the solution:

这是萨尔回答的后续行动,他/她在那里提供了解决方案:

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

This is useful also when converting a non-typical C-String to a std::string

这在将非典型 C-String 转换为 std::string 时也很有用

A use case for me was having a pre-allocated char array (like C-String), but it's not NUL terminated. (i.e. SHA digest). The above syntax allows me to specify the length of the SHA digest of the char array so that std::string doesn't have to look for the terminating NUL char, which may or may not be there.

我的一个用例是有一个预先分配的字符数组(如 C-String),但它不是 NUL 终止的。(即SHA摘要)。上面的语法允许我指定 char 数组的 SHA 摘要的长度,以便 std::string 不必寻找终止的 NUL 字符,它可能存在也可能不存在。

Such as:

如:

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

回答by freeze

This works fine:

这工作正常:

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

回答by zar

All other answers didn't quite address what I was looking for which was to convert CStringon the fly as opposed to store the result in a variable.

所有其他答案都没有完全解决我正在寻找的问题,即CString即时转换而不是将结果存储在变量中。

The solution is similar to above but we need one more step to instantiate a nameless object. I am illustrating with an example. Here is my function which needs std::stringbut I have CString.

解决方案与上面类似,但我们还需要一个步骤来实例化一个无名对象。我用一个例子来说明。这是我需要的功能,std::string但我有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;
}

How to call it when you have a CString?

当你有一个时如何调用它CString

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

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

Note that the last line is not a direct typecast but we are creating a nameless std::stringobject and supply the CStringvia its constructor.

请注意,最后一行不是直接类型转换,而是我们正在创建一个无名std::string对象并CString通过其构造函数提供 。