如何将LPCTSTR转换为std::string?

15

我有一个 LPCTSTR,想调用一个需要 std::string 参数的函数。

我需要进行什么样的转换?

7个回答

21

冰山一角

LPCTSTR 可以是单字节或多字节字符串(取决于编译过程中是否定义了 UNICODE 常量),而 std::string 的用户(包括您的函数)通常使用它来保存单字节字符串。

你需要进行两次转换:一次转换为 LPCSTR(非 UNICODE 构建),一次转换为 LPCWSTRUNICODE 构建)。第一个转换很简单:

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编码的字符串。但是“按照惯例”,我假设它也希望得到一个单字节编码的字符串。


谢谢!是的,它是一个已启用 #define UNICODE 的 UNICODE 构建。我正在调用的函数将使用 std::string 作为文件名,当调用 std::fstream::open() 时 - 看起来 WideCharToMultiByte 是正确的选择。不过那是很多参数 - 可以扩展一下您的答案并包含调用该函数的示例吗? - GrahamS
@Jon:实际上,这是微软的扩展。如果您已经使用了LPCTSTR,那么使用fstream:: fstream(const wchar_t *filename)不会进一步限制自己。事实上,通过该重载,可以说fstream:: fstream已经采用了LPCTSTR - MSalters
@MSalters:我从未在 Windows 上下文之外看到过 LPCTSTR,所以我假设 WideCharToMultiByte 不是问题——除非您将其他内容称为 MS 扩展?此外,答案解决了原始问题(没有提到 fstream)。 - Jon
@Jon:不适用于UTF-8,因为它仍然是Unicode。这就是为什么您不能在CP_UTF8中使用WC_NO_BEST_FIT_CHARS的原因。但是,您在这里也不能使用CP_UTF8; std :: fstream :: fstream(char const *)将使用CP_ACP进行转换回WCHAR。 - MSalters
@MSalters: 哎呀——我上个评论犯了一个错误。我是指“W到MB”,尤其是“W到SB”的情况。所以你当然是对的,UTF不是问题所在。 - Jon
显示剩余6条评论

16

一行代码实现:

std::string s = CT2A( lpctstr );

2

务实的方法:

     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
5
在美国和西欧地区(ACP = latin-1),这是可以“工作”的。但在其他地方,它会以有趣的方式出现错误。 - MSalters
1
同意。请参见“务实方法”标题和免责声明“请参阅其他答案以获取出色的背景知识!”(注意感叹号)。我投票支持您的评论,这样它就会更加显眼。 - sehe

2

从您的评论中可以看出:“我调用的函数将使用std::string作为文件名调用std::fstream::open()”

这是错误的。该函数实际上应该接受一个tstring(定义为typedef std::basic_string<TCHAR> tstring)。有许多Windows文件的名称无法表示为非Unicode字符集。例如,如果<myUserName>包含非ANSI字符,那么在\User\<myusername\My Documents\下的所有文件都无法表示(您真的不想告诉用户他的名字有问题!)

但一旦您更改为tstring,它就可以正常工作了。您仍然会得到相同的std::fstream对象。


1
+1 说得好。不幸的是,我不负责那个函数所在的库,所以我不能改变它,但我会向作者提出这个观点,谢谢。 - GrahamS

1

LPCTSTR是Windows定义的一个类型,大致意思是“指向常量字符类型字符串的长指针”。我不确定T代表什么,但它与项目的字符集有关。

如果您的项目使用Unicode字符集,则此类型为const wchar_t*,每个字符使用两个字节。如果您的项目使用多字节字符集,则此类型为const char*,每个字符使用一个字节。

很可能您的项目字符集是Unicode,因此LPCTSTRconst 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);

1
这段代码应该将LPWSTR转换为char*/std::string。
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);

我走的是另一条路线:从LPCTSTRstd::string - GrahamS
抱歉,我刚才才意识到;我正在寻找另一种转换代码片段。 - marchelbling

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接