1

我对 C 字符串和宽 C 字符串有点困惑。为了这个问题,假设我使用 Microsoft Visual Studio 2010 Professional。如果我的任何信息不正确,请告诉我。

我有一个带有 const wchar_t* 成员的结构,用于存储名称。

struct A
{
    const wchar_t* name;
};

当我为对象'a'分配一个名称时:

int main()
{
    A a;

    const wchar_t* w_name = L"Tom";
    a.name = w_name;

    return 0;
}

那只是将 w_name 指向的内存地址复制到 a.name 中。现在 w_name 和 a.name 都是指向内存中相同地址的宽字符指针。

如果我是正确的,那么我想知道如何处理这种情况。我正在使用 tinyxml2 从 XML 属性中读取 C 字符串。

tinyxml2::XMLElement* pElement;
// ...
const char* name = pElement->Attribute("name");

获得 C 字符串后,我将其转换为宽字符串,如下所示:

size_t newsize = strlen(name) + 1;
wchar_t * wcName = new wchar_t[newsize];
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, wcName, newsize, name, _TRUNCATE);

a.name = wcName;

delete[] wcName;

如果到目前为止我是正确的,那么该行:

 a.name = wcName;

只是将数组 wcName 的第一个字符的内存地址复制到 a.name 中。但是,我在分配此指针后直接删除 wcName,这将使其指向垃圾。

如何将我的 C 字符串转换为宽字符 C 字符串,然后将其分配给 a.name?

4

3 回答 3

3

最简单的方法可能是让你name变量管理内存。反过来,这很容易通过将其声明为

std::wstring name;

这些家伙没有独立内容和对象变异的概念,也就是说,你不能真正制作单个角色const,制作整个对象const会阻止它被分配到。

于 2012-11-15T20:04:17.437 回答
1

可以在使用 a 时执行此操作,而std::wstring无需依赖额外的临时转换缓冲区分配和销毁。除非您明显担心堆碎片或在有限的系统(又名 Windows Phone)上,否则这不是非常重要。它只需要在正面进行一些设置。让标准库为您管理内存(稍微推动一下)。

class A
{
   ...
   std::wstring a;
};


// Convert the string (I'm assuming it is UTF8) to wide char
int wlen = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, NULL);
if (wlen > 0)
{
    // reserve space. std::wstring gives us the terminator slot
    // for free, so don't include that. MB2WC above returns the
    // length *including* the terminator.
    a.resize(wlen-1);
    MultiByteToWideChar(CP_UTF8, 0, name, -1, &a[0], wlen);
}
else
{   // no conversion available/possible.
    a.clear();
}

在完整的旁注中,您可以构建 TinyXML 以使用标准库std::string而不是char *,这在这里并没有真正帮助您,但可能会在以后为您节省大量strlen()调用。

于 2012-11-15T21:02:21.587 回答
0

正如您正确提到a.name的,它只是一个指针,它不假设任何分配的字符串存储。您必须使用new静态/范围数组手动管理它。

要摆脱这些无聊的事情,只需使用可用的字符串类之一:CStringW来自 ATL(易于使用但特定于 MS)或std::wstring来自 STL(C++ 标准,但不太容易转换char*):

#include <atlstr.h>

// Conversion ANSI -> Wide is automatic
const CStringW name(pElement->Attribute("name"));    

不幸的是,std::wstring使用 withchar*并不是那么容易。请参阅此处的转换函数:How to convert std::string to LPCWSTR in C++ (Unicode)

于 2012-11-15T20:21:57.270 回答