为什么我不能读取长度超过4094个字符的UTF-16文件?

一些信息:

  • 我只在Linux上试过
  • 我已经用GCC(7.2.0)和Clang(3.8.1)
  • 它需要C ++ 11或更高的理解

当我运行它会发生什么

我得到期望的string“abcd”重复,直到它达到4094个字符的位置。 之后,它输出的是这个符号“?” 直到文件结束。

我怎么看这个?

我认为这不是预期的行为,它必须是一个错误的地方。

您可以testing的代码:

#include <iostream> #include <fstream> #include <locale> #include <codecvt> void createTestFile() { std::ofstream file ("utf16le.txt", std::ofstream::binary); if (file.is_open()) { uint16_t bom = 0xFEFF; // UTF-16 little endian BOM uint64_t abcd = 0x0064006300620061; // UTF-16 "abcd" string file.write((char*)&bom,2); for (size_t i=0; i<2000; i++) { file.write((char*)&abcd,8); } file.close(); } } int main() { //createTestFile(); // uncomment to make the test file std::wifstream file; std::wstring line; file.open("utf16le.txt"); file.imbue(std::locale(file.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>)); if (file.is_open()) { while (getline(file,line)) { std::wcout << line << std::endl; } } } 

这看起来像一个库的bug。 按照gcc 7.1.1使用gdb编译的示例程序:

 (gdb) n 28 while (getline(file,line)) { (gdb) n 29 std::wcout << line << std::endl; (gdb) p line.size() $1 = 8000 

如预期的那样,读取8000个字符。 但是之后:

 (gdb) p line[4092] $18 = (__gnu_cxx::__alloc_traits<std::allocator<wchar_t> >::value_type &) @0x628240: 97 L'a' (gdb) p line[4093] $19 = (__gnu_cxx::__alloc_traits<std::allocator<wchar_t> >::value_type &) @0x628244: 98 L'b' (gdb) p line[4094] $20 = (__gnu_cxx::__alloc_traits<std::allocator<wchar_t> >::value_type &) @0x628248: 25344 L'挀' (gdb) p line[4095] $21 = (__gnu_cxx::__alloc_traits<std::allocator<wchar_t> >::value_type &) @0x62824c: 25600 L'搀' (gdb) p line[4096] $22 = (__gnu_cxx::__alloc_traits<std::allocator<wchar_t> >::value_type &) @0x628250: 24832 L'愀' 

line[4092]line[4093]看起来不错。 但是,我看到line[4094]line[4095]line[4096] ,包含63006500 ,而不是00630065

所以,这实际上是从字符4094开始,而不是从4096开始。 我甩了二进制UTF-16文件,它看起来对我来说是正确的。 BOM标记后面是整个文件内容的一致性排序。

唯一令人困惑的是为什么clang和gcc都会受到影响,但Google的一个快速搜索表明,clang也使用gcc的libstdc ++,至少直到最近。 所以,这看起来像一个libstdc ++的bug。