CString
is best handig, terwijl std::string
beter compatibel is met STL-container. Ik gebruik hash_map
. hash_map
ondersteunt echter geen CString
s als sleutels, dus ik wil de CString
converteren naar een std::string
.
Het schrijven van een CString
hash-functie lijkt veel tijd te kosten.
CString -----> std::string
Hoe kan ik dit doen?
std::string -----> CString:
inline CString toCString(std::string const& str)
{
return CString(str.c_str());
}
Heb ik gelijk?
BEWERKEN:
Hier zijn meer vragen:
Hoe kan ik wstring
converteren naar CString
en vice versa?
// wstring -> CString
std::wstring src;
CString result(src.c_str());
// CString -> wstring
CString src;
std::wstring des(src.GetString());
Is er een probleem hiermee?
Hoe kan ik bovendien converteren van std::wstring
naar std::string
en vice versa?
Antwoord 1, autoriteit 100%
Volgens CodeGuru:
CString
naar std::string
:
CString cs("Hello");
std::string s((LPCTSTR)cs);
MAAR:std::string
kan niet altijd construeren vanuit een LPCTSTR
. d.w.z. de code zal mislukken voor UNICODE-builds.
Aangezien std::string
alleen kan construeren uit LPSTR
/ LPCSTR
, kan een programmeur die VC++ 7.x of beter gebruikt conversie gebruiken klassen zoals CT2CA
als tussenpersoon.
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
naar CString
: (Van Veelgestelde vragen over CString van Visual Studio…)
std::string s("Hello");
CString cs(s.c_str());
CStringT
kan construeren uit zowel tekenreeksen als tekenreeksen met brede tekens. dwz het kan converteren van char*
(dwz LPSTR
) of van wchar_t*
(LPWSTR
).
Met andere woorden, char-specialisatie (van CStringT
) dwz CStringA
, wchar_t
-specilisatie CStringW
, en TCHAR
-specialisatie CString
kan worden opgebouwd uit char
of brede tekens, null beëindigd (null-beëindiging is hier erg belangrijk )tekenreeksbronnen.
Hoewel IInspectablehet gedeelte “null-termination” wijzigt in de opmerkingen:
NUL-beëindiging is niet vereist.
CStringT
heeft conversieconstructors die een expliciet lengteargument hebben. Dit betekent ook dat uCStringT
-objecten kunt maken vanstd::string
-objecten met ingeslotenNUL
-tekens.
Antwoord 2, autoriteit 36%
Los dat op door std::basic_string<TCHAR>
te gebruiken in plaats van std::string
en het zou goed moeten werken, ongeacht je tekeninstelling.
Antwoord 3, autoriteit 6%
Het is efficiënter om CString
te converteren naar std::string
met behulp van de conversie waarbij de lengte is opgegeven.
CString someStr("Hello how are you");
std::string std(someStr, someStr.GetLength());
In een strakke lus zorgt dit voor een aanzienlijke prestatieverbetering.
Antwoord 4, autoriteit 5%
Als je iets meer C++-achtigs wilt, dan is dit wat ik gebruik. Hoewel het afhankelijk is van Boost, is dat slechts voor uitzonderingen. U kunt degenen die het verlaten eenvoudig verwijderen om alleen afhankelijk te zijn van de STL en de WideCharToMultiByte()
Win32 API-aanroep.
#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);
}
Antwoord 5, autoriteit 4%
Is er eenprobleem?
Er zijn verschillende problemen:
CString
is een sjabloonspecialisatie van CStringT. Afhankelijk van het BaseTypedat het tekentype beschrijft, zijn er twee concrete specialisaties:CStringA
(met behulp vanchar
) enCStringW
(met behulp vanwchar_t
).- Hoewel
wchar_t
op Windows alom wordt gebruikt om UTF-16-gecodeerde code-eenheden op te slaan, is het gebruik vanchar
dubbelzinnig. De laatste slaat gewoonlijk ANSI-gecodeerde tekens op, maar kan ook ASCII-, UTF-8- of zelfs binaire gegevens opslaan. - We kennen de tekencodering (of zelfs het tekentype) van
CString
niet (die wordt bestuurd door het preprocessor-symbool_UNICODE
), waardoor de vraag dubbelzinnig is. We kennen ook de gewenste tekencodering vanstd::string
niet. - Conversie tussen Unicode en ANSI is inherent verliesgevend: ANSI-codering kan alleen een subset van de Unicode-tekenset vertegenwoordigen.
Om deze problemen aan te pakken, ga ik ervan uit dat wchar_t
UTF-16-gecodeerde code-eenheden zal opslaan en char
UTF-8-octetreeksen zal bevatten. Dat is de enige redelijke keuze die u kunt maken om ervoor te zorgen dat bron- en bestemmingsreeksen dezelfde informatie behouden, zonder de oplossing te beperken tot een subset van de bron- of doeldomeinen.
De volgende implementaties converteren tussen CStringA
/CStringW
en std::wstring
/std::string
mapping van UTF-8 naar UTF-16 en vice versa:
#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 };
}
De overige twee functies construeren C++-tekenreeksobjecten van MFC-tekenreeksen, waarbij de codering ongewijzigd blijft. Merk op dat hoewel de vorige functies niet overweg kunnen met ingesloten NUL-tekens, deze functies daar immuun voor zijn.
#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() };
}
Antwoord 6, autoriteit 3%
(Sinds VS2012 …en in ieder geval tot VS2017 v15.8.1)
Omdat het een MFC-project is & CString is een MFC-klasse, MS biedt een technische opmerking TN059: MFC MBCS/Unicode gebruiken Conversiemacro’sen algemene conversiemacro’s:
A2CW (LPCSTR) -> (LPCWSTR)
A2W (LPCSTR) -> (LPWSTR)
W2CA (LPCWSTR) -> (LPCSTR)
W2A (LPCWSTR) -> (LPSTR)
Gebruik:
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" **
}
—
Voetnoten:
(1) Om ervoor te zorgen dat de conversie-macro’s ruimte hebben om de tijdelijke lengte op te slaan, is het noodzakelijk om een lokale variabele genaamd _convert
te declareren die dit doet in elke functie die de conversie gebruikt macro’s. Dit wordt gedaan door de macro USES_CONVERSION
aan te roepen. In VS2017 MFC-code (atlconv.h) ziet het er als volgt uit:
#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
Antwoord 7, autoriteit 2%
Dit werkt prima:
//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
return CT2A(cst.GetString());
}
Antwoord 8
Dit is een vervolg op het antwoord van Sal, waar hij/zij de oplossing heeft gegeven:
CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());
Dit is ook handig bij het converteren van een niet-typische C-String naar een std::string
Een use case voor mij was het hebben van een vooraf toegewezen char-array (zoals C-String), maar het is niet NUL-beëindigd. (d.w.z. SHA-digest).
Met de bovenstaande syntaxis kan ik de lengte van de SHA-digest van de char-array specificeren, zodat std::string niet hoeft te zoeken naar de afsluitende NUL-char, die er al dan niet is.
Zoals:
unsigned char hashResult[SHA_DIGEST_LENGTH];
auto value = std::string(reinterpret_cast<char*>hashResult, SHA_DIGEST_LENGTH);
Antwoord 9
van dit bericht (Bedankt Mark Ransom)
CString converteren naar string (VC6)
Ik heb dit getest en het werkt prima.
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;
}
Antwoord 10
U kunt CT2CA
. gebruiken
CString datasetPath;
CT2CA st(datasetPath);
string dataset(st);
Antwoord 11
om CString to std::string
. U kunt dit formaat gebruiken.
std::string sText(CW2A(CSText.GetString(), CP_UTF8 ));
Antwoord 12
Werkt voor mij:
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();
}
Antwoord 13
Alle andere antwoorden kwamen niet helemaal overeen met wat ik zocht, namelijk om CString
on-the-fly te converteren in plaats van het resultaat in een variabele op te slaan.
De oplossing is vergelijkbaar met hierboven, maar we hebben nog een stap nodig om een naamloos object te instantiëren. Ik illustreer met een voorbeeld. Hier is mijn functie die std::string
nodig heeft, maar ik heb 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;
}
Hoe noem je het als je een CString
hebt?
std::string firstName = "First";
CString lastName = _T("Last");
writeLog( firstName + ", " + std::string( CT2A( lastName ) ) );
Merk op dat de laatste regel geen directe typecast is, maar we maken een naamloos std::string
object en leveren de CString
via zijn constructor.
Antwoord 14
Als u eenvoudig wilt converteren tussen andere typen tekenreeksen, is het misschien de _bstr_t
klasse zou meer geschikt zijn? Het ondersteunt conversie tussen char
, wchar_t
en BSTR
.
Antwoord 15
Een interessante benadering is om CString
naar CStringA
te casten in een string
-constructor. In tegenstelling tot std::string s((LPCTSTR)cs);
werkt dit zelfs als _UNICODE
is gedefinieerd. Als dat echter het geval is, zal dit de conversie van Unicode naar ANSI uitvoeren, dus het is onveilig voor hogere Unicode-waarden buiten de ASCII-tekenset. Een dergelijke conversie is onderhevig aan de preprocessordefinitie _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
. https://msdn.microsoft.com/en-us/library/5bzxfsea. aspx
CString s1("SomeString");
string s2((CStringA)s1);
Antwoord 16
Je kunt CString
vrij casten naar const char*
en het dan toewijzen aan een std::string
als volgt:
CString cstring("MyCString");
std::string str = (const char*)cstring;