我有一个 LPCTSTR
,想调用一个需要 std::string
参数的函数。
我需要进行什么样的转换?
我有一个 LPCTSTR
,想调用一个需要 std::string
参数的函数。
我需要进行什么样的转换?
LPCTSTR
可以是单字节或多字节字符串(取决于编译过程中是否定义了 UNICODE
常量),而 std::string
的用户(包括您的函数)通常使用它来保存单字节字符串。
你需要进行两次转换:一次转换为 LPCSTR
(非 UNICODE
构建),一次转换为 LPCWSTR
(UNICODE
构建)。第一个转换很简单:
std::string convert(LPCSTR str) {
return std::string(str);
}
第二个函数需要先使用WideCharToMultiByte
将其输入参数转换为另一种编码。不要被名称吓到,结果可以是单字节字符字符串;这取决于CodePage
参数。您需要使用单字节编码的代码页,例如CP_ACP
。
更新:WideCharToMultiByte
示例
请注意,如果输入字符串包含目标编码代码页中不存在的字符,则准确地转换为单字节编码技术上是不可能的。由于您提到它将用于文件系统函数,如果文件路径包含这样的字符,则转换将不会 100%准确,随后的函数调用将失败。
std::string MBFromW(LPCWSTR pwsz, UINT cp) {
int cch = WideCharToMultiByte(cp, 0, pwsz, -1, 0, 0, NULL, NULL);
char* psz = new char[cch];
WideCharToMultiByte(cp, 0, pwsz, -1, psz, cch, NULL, NULL);
std::string st(psz);
delete[] psz;
return st;
}
注意:上面的示例代码只是我随手写的,不符合生产级别的质量。显而易见的一个缺陷是它没有异常安全。这可能会杀死所有漂亮的紫色独角兽。仅把它作为一个示例使用。
裸露的事实是,std::string
可以很好地用于多字节编码(如UTF8)-- 你甚至可以使用它来保存宽字符字符串,因为它本质上只是一个二进制安全的字节数组。
问题在于 适用于std::string
的STL函数期望其内容以单字节编码形式存在,如果不是这种情况,它们将无法产生正确的结果。
进一步地,我们不知道你的接收std::string
参数的函数期望什么样的字符串 -- 它可能希望得到一个UTF-8编码的字符串。但是“按照惯例”,我假设它也希望得到一个单字节编码的字符串。
一行代码实现:
std::string s = CT2A( lpctstr );
务实的方法:
LPCTSTR input;
std::string s;
#ifdef UNICODE
std::wstring w;
w = input;
s = std::string(w.begin(), w.end()); // magic here
#else
s = input;
#endif
请参考其他答案以获取优秀的背景知识!
s = w
行出现了error C2679: binary '=' : no operator found which takes a right-hand operand of type 'std::wstring' (or there is no acceptable conversion)
错误,我需要更多的魔法吗? - GrahamS从您的评论中可以看出:“我调用的函数将使用std::string作为文件名调用std::fstream::open()”
这是错误的。该函数实际上应该接受一个tstring
(定义为typedef std::basic_string<TCHAR> tstring
)。有许多Windows文件的名称无法表示为非Unicode字符集。例如,如果<myUserName>
包含非ANSI字符,那么在\User\<myusername\My Documents\
下的所有文件都无法表示(您真的不想告诉用户他的名字有问题!)
但一旦您更改为tstring
,它就可以正常工作了。您仍然会得到相同的std::fstream
对象。
LPCTSTR
是Windows定义的一个类型,大致意思是“指向常量字符类型字符串的长指针”。我不确定T代表什么,但它与项目的字符集有关。
如果您的项目使用Unicode字符集,则此类型为const wchar_t*
,每个字符使用两个字节。如果您的项目使用多字节字符集,则此类型为const char*
,每个字符使用一个字节。
很可能您的项目字符集是Unicode,因此LPCTSTR
是const wchar_t*
。由于std::string
每个字符使用一个字节,无法容纳这种每个字符使用两个字节的字符串。然而,std::wstring
可以。
如果您需要将const wchar_t*
转换为const char*
以允许其分配给字符串,可以使用像wcstombs
这样的函数来完成。如果您在项目中包含ATL(特别是atlconv.h
),它提供了更方便的宏来完成此操作:
USES_CONVERSION;
const wchar_t* = L"Wide string";
std::string str = W2A(value);
LPWSTR input = L"whatever";
int cSize = WideCharToMultiByte (CP_ACP, 0, input, wcslen(input), NULL, 0, NULL, NULL);
std::string output(static_cast<size_t>(cSize), '\0');
WideCharToMultiByte (CP_ACP, 0, input, wcslen(input),
reinterpret_cast<char*>(&output[0]), cSize, NULL, NULL);
这段代码片段可以将单字节的std::string转换为LPWSTR。
std::string input = "whatever";
//computing wchar size:
int wSize = MultiByteToWideChar (CP_ACP, 0, (LPCSTR) input.c_str (), -1, 0, 0);
//allocating memory for wchar:
LPWSTR output = new WCHAR[wSize];
//conversion from string to LPWSTR:
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED , (LPCSTR) input.c_str (), -1, output, wSize);
LPCTSTR
到std::string
。 - GrahamS
#define UNICODE
的 UNICODE 构建。我正在调用的函数将使用std::string
作为文件名,当调用std::fstream::open()
时 - 看起来 WideCharToMultiByte 是正确的选择。不过那是很多参数 - 可以扩展一下您的答案并包含调用该函数的示例吗? - GrahamSLPCTSTR
,那么使用fstream:: fstream(const wchar_t *filename)
不会进一步限制自己。事实上,通过该重载,可以说fstream:: fstream
已经采用了LPCTSTR
。 - MSaltersLPCTSTR
,所以我假设WideCharToMultiByte
不是问题——除非您将其他内容称为 MS 扩展?此外,答案解决了原始问题(没有提到fstream
)。 - Jon