c++ - 为什么我无法读取长度超过 4094 个字符的 UTF-16 文件?

标签 c++ linux utf-16 wstring wifstream

一些信息:

  • 我只在 Linux 上试过这个
  • 我已经尝试过 GCC (7.2.0) 和 Clang (3.8.1)
  • 据我了解,它需要 C++11 或更高版本

我运行它时会发生什么

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

我对此有何看法?

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

可用于测试的代码:

#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;
    }
  }
}

最佳答案

对我来说,这看起来像是一个库错误。使用 gdb 逐步执行 gcc 7.1.1 编译的示例程序:

(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],包含 630064006500,而不是 006300640065

所以,实际上从字符 4094 而不是 4096 开始就搞砸了。我转储了二进制 UTF-16 文件,它看起来对我来说是正确的。 BOM 标记之后是文件全部内容的一致字节序。

唯一令人费解的是,为什么据说 clang 和 gcc 都会受到影响,但 Google 的快速搜索表明,至少直到最近,clang 还使用 gcc 的 libstdc++。所以,对我来说,这看起来像是一个 libstdc++ 错误。

关于c++ - 为什么我无法读取长度超过 4094 个字符的 UTF-16 文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45870778/

相关文章:

c++ - Xcode 5 makefile 项目中的 Doxygen 文档

c++ - 在 Linux 中为 c++ 使用 gprof -f 选项

c++ - 如何生成用于测试快速排序最佳案例的数组?

c++ - C++ 头文件中的内联函数

c++ - 检查 unordered_set 是否包含其他 unordered_set 中的所有元素 - C++

c - 使用 linux 系统视频设备使用 ffmpeg 库以编程方式流式传输

php - 权限被拒绝在本地运行我的项目 Zend Framework

java - 统一码问题 : How to convert ’ to ’ in the response from HttpClient?

c - 如何在 C 中引用 UTF-16 字符?

C++ 对 MBCS 使用 std::string 函数,对 UTF-16 使用 std::wstring 函数