C++ WCHAR 操作

Posted

技术标签:

【中文标题】C++ WCHAR 操作【英文标题】:C++ WCHAR manipulations 【发布时间】:2012-11-01 20:26:11 【问题描述】:

我正在用 C++ 开发一个小型 Win32 应用程序。 我很久以前就研究过C++基础知识,所以现在我完全被C++中的字符串弄糊涂了。没有WCHARTCHAR,只有charString。 经过一番调查,我决定不使用TCHAR

我认为我的问题很简单,但我找不到明确的指导如何在 C++ 中操作字符串。受过去几年 php 编码的影响,我原本以为字符串操作很简单,但结果错了!

简单地说,我只需要将新数据放入一个字符串中。

    WCHAR* cs = L"\0";
    swprintf( cs, "NEW DATA" );

这是我的第一次尝试。在调试我的应用程序时,我调查过 swprintf 仅将前 2 个字符放入我的 cs var。我已经通过这种方式解决了我的问题:

    WCHAR cs[1000];
    swprintf( cs, "NEW DATA" );

但通常这个技巧可能会失败,因为在我的情况下,新数据不是常量值而是另一个变量,它可能比 1000 字符长更宽。我的代码是这样的:

    WCHAR cs[1000];
    WCHAR* nd1;
    WCHAR* nd2;
    wcscpy(nd1, L"Some value");
    wcscpy(nd2, L"Another value"); // Actually these vars stores the path for user selected folder
    swprintf( cs, "The paths are %s and %s", nd1, nd2);

在这种情况下,nd1 和 nd2 的总字符数可能超过 1000 个字符,因此关键数据将丢失。

问题是如何将我需要的所有数据复制到以这种方式声明的 WCHAR 字符串 WCHAR* wchar_var; 而不会丢失任何内容?

附:由于我是俄罗斯人,所以问题可能不清楚。现在让我谈谈这一点,我将尝试更清楚和更复杂地解释我的问题。

【问题讨论】:

您应该使用wchar_tstd::wstring。并阅读有关指针的更多信息,因为您的最后一个代码 sn-p 使用未初始化的指针复制数据,这意味着您可以覆盖进程内存中的任何内容。 我一定会读到关于指针的! 我添加了标签string 那你应该知道使用未初始化的指针是不好的吧? 是的,当然!我在学校学习的时候学过指针,但这是很久以前的事了,所以我需要更新一下知识。非常感谢! 【参考方案1】:

当您使用WCHAR* 时,您正在调用未定义的行为,因为您有一个指针但没有使它指向任何有效的东西。您需要找出结果字符串的长度并为字符串动态分配空间。例如:

WCHAR* cs;
WCHAR* nd1;
WCHAR* nd2;

nd1 = new WCHAR[lstrlen(L"Some value") + 1]; // +1 for the null terminator
nd2 = new WCHAR[lstrlen(L"Another value") + 1];
cs = new WCHAR[lstrlen(L"The paths are  and ") + lstrlen(nd1) + lstrlen(nd2) + 1];

wcscpy(nd1, L"Some value");
wcscpy(nd2, L"Another value"); // Actually these vars stores the path for user selected folder
swprintf( cs, L"The paths are %s and %s", nd1, nd2);

delete[] nd1;
delete[] nd2;
delete[] cs;

但这非常丑陋且容易出错。如前所述,您应该改用std::wstring,如下所示:

std::wstring cs;
std::wstring nd1;
std::wstring nd2;

nd1 = L"Some value";
nd2 = L"Another value";
cs = std::wstring(L"The paths are ") + nd1 + L" and " + nd2;

【讨论】:

我考虑过“丑陋的方式”,但是因为这真的很丑,所以你提供的第二种方式对我来说就像埃尔多拉多!谢谢!【参考方案2】:

建议使用 ATL CStringW 类而不是原始的WCHAR,这样更方便。 CString 是动态分配的 C 字符串的包装器。它会在每次操作后适当地管理字符串长度和分配的内存缓冲区,所以你不会关心它。

典型用法:

#include <atlstr.h>

CStringW s;
s.Format(L"The paths are %s and %s", L"Some value", L"Another value");
const WCHAR* wstr = s.GetString(); // To pass to some API that need WCHAR

#include <atlstr.h>

CStringW s(L"The paths are ");
s += L"Some value";
s += L" and ";
s += L"Another value";
const WCHAR* wstr = s.GetString(); // To pass to some API that need WCHAR

【讨论】:

您可以简单地将CString 实例传递给需要const WCHAR* 的API,因为CString 为此提供了一个方便的隐式const wchar_t* 运算符。 @Mr.C64 是的,当然,但最好使用明确的GetString() 不,CString::GetString() 仅在具有printf 类似格式字符串和%sswprintf() 这样的上下文中才有意义。我只是直接将CString 实例作为参数传递给带有LPCWSTR 参数的函数。 首先,将CString 传递为printf-like func 参数也将起作用,因为CStringchar*/wchar_t* 是二进制兼容的。其次,使用隐式转换是危险且令人困惑的。应改为使用显式转换。那是因为std::string 没有这样的const char*() 运算符。 CStringprintf() 类似的函数一起工作的事实是一种“黑客”;它不是健壮的代码。甚至MSDN discourages that use and suggests an explicit cast(但我发现调用str.GetString()static_cast&lt;const wchar_t*&gt;(str) 更好)。此外,将CString 传递给const wchar_t* 参数很好(对我来说,CString str; ... SetWindowText(hWnd, str); 可以,但SetWindowText(hWnd, str.GetString());代码)。【参考方案3】:

在现代 Windows 编程中,可以忽略 TCHAR 而使用 wchar_t (WCHAR) 和 Unicode UTF-16。

TCHAR 是过去的模型,当您想要拥有单一代码库并生成 ANSI/MBCS 和 Unicode 版本时,会更改一些预处理器开关,例如 _UNICODEUNICODE。)

无论如何,您应该使用 C++ 和方便的 字符串类 来简化您的代码。您可以使用ATL::CString(对应于Unicode 版本中的CStringW,这是自VS2005 以来的默认设置),或STL 的std::wstring

使用CString,您可以:

CString str1 = L"Some value";
CString str2 = L"Another value";
CString cs;
cs.Format(L"The paths are %s and %s", str1.GetString(), str2.GetString());

CString 还提供了适当的 operator+ 重载来连接字符串(因此您不必计算结果字符串的总长度,为目标字符串动态分配缓冲区或检查现有缓冲区大小,调用 @ 987654334@,wcscat,别忘了释放缓冲区等)

您可以简单地将CString 的实例传递给需要const wchar_t* (LPCWSTR/PCWSTR) 参数的Win32 API,因为CString 提供了到const wchar_t* 的隐式转换运算符。

【讨论】:

我暂时不熟悉 ATL。而且我还决定在 Windows 的其他应用程序中使用 .NET。我想 .NET 中还有另一个字符串例程,不是吗? 您无需熟悉 ATL 即可使用 CString。您可以只使用#include &lt;atlstr.h&gt; 并使用CString 及其方便的功能(包括从应用程序资源加载字符串)。 CStringstd::wstring 更好地集成到 Win32 编程中。 非常感谢!我现在就试试

以上是关于C++ WCHAR 操作的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中获取 `wchar_t*` 的长度

C++ 中的 LPWSTR、wchar_t* 和无符号短指针

C++中char和wchar_t转换

重新声明 C++ 内置类型'wchar_t' windows 10 glut cpp

来自 wchar_t* 的 C++ Win32 GDI+ 拉绳

GLUT 问题:错误重新声明 C++ 内置类型“wchar_t”