1

前几天,我正在编写类似于以下内容的代码:

wchar_t buffer[1024];
std::wifstream input(L"input.txt");

while (input.good())
{
    input::getline(buffer, 1024);
    // ... do stuff...
}

input.close();

我发现,在第一次调用 之后getlinebuffer它包含正确的数据(UTF-16 LE)字节,但它没有buffer被视为 wchar_t 数组,而是神奇地转换为字节数组。我reinterpret_cast<wchar_t *>(buffer)得到了我想要的结果。

然后下一次调用getline... 这次,缓冲区再次被视为一个字节数组,但字节是倾斜的。我期待看到0x31 0x00 0x32 0x00 0x33 0x00,但我看到了0x00 0x31 0x00 0x32 0x00 0x33

现在,我可以理解如果字符具有可变长度编码,事情可能会如何扭曲......但是我的 input.txt 文件中的所有字符都是 ASCII,因此每个字符都可以用 2 个字节编码(使用 UTF16-LE)。为什么偏斜?

SO 上的一位回答者告诉我,我应该像这样灌输流:

std::wifstream fin("text.txt", std::ios::binary);
// apply facet
fin.imbue(std::locale(fin.getloc(),
          new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>));

确实,这完全解决了我的问题。如果您正在处理的所有字符都具有固定长度的编码,我不明白为什么需要注入?

其次,灌输的第二个参数似乎是内存泄漏?!如果我在堆栈上分配一个std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>对象并将其地址传递给 imbue,那么一切似乎都可以工作,直到我的堆栈变量超出范围(就在主右括号之前)。应用程序崩溃,抱怨某些函数正在调用纯虚函数。如果我使用提供的代码并在 main 返回之前在内存上调用 delete,我会看到相同的行为。

提前感谢您的评论和回答。

4

1 回答 1

1

您的文件包含类似31 00 32 00 33 00 0A 00 34 00 .... 0A是换行符。

使用默认codecvt方面,每个字节都单独转换为 Unicode。所以31变成U+003100变成U+0000等等。getline停在0A字节。

下一个getline调用从前一个调用中断的地方继续:00变为U+0000,依此类推。

于 2013-11-01T01:50:45.120 回答