我如何读取0xFF文件与libc++ istream_iterator



考虑以下示例代码:

#include <iostream>
using namespace std;
int main()
{
  istreambuf_iterator<char> eos;
  istreambuf_iterator<char> iit(cin.rdbuf());
  int i;
  for (i = 0; iit != eos; ++i, ++iit) {
    cout << *iit;
  }
  cout << endl << i << endl;
}

和一个包含以下内容的输入文件:"fooxffbar":

$ hexdump testin
0000000 66 6f 6f ff 62 61 72
0000007

现在使用clang libc++ vs gnu libstdc++进行测试:

$ make test
clang++ -std=c++11 -stdlib=libc++ -Wall -stdlib=libc++ -o bug-libcc bug.cpp
clang++ -std=c++11 -stdlib=libc++ -Wall -stdlib=libstdc++ -o bug-libstd bug.cpp
./bug-libcc < testin
foo
3
./bug-libstd < testin
foo�bar
7

如您所见,libc++版本认为0xff是流的结束,并停止读取。这就引出了几个问题。

1)这是libc++中的一个bug,我应该报告吗?我在谷歌上搜索现有的漏洞,一无所获。

2)是否有一个好的方法来解决这个问题?

编辑

下面的代码可以工作:

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
  ifstream ifs ("testin", ios::binary);
  istreambuf_iterator<char> eos;
  istreambuf_iterator<char> iit(ifs.rdbuf());
  int i;
  for (i = 0; iit != eos; ++i, ++iit) {
    cout << *iit;
  }
  cout << endl << i << endl;
}

让我相信这是一个二进制转换问题,但这并不能解释为什么libstdc++能正常工作。

EDIT2

使用没有二进制文件的文件也可以:

ifstream ifs ("testin");

所以肯定有什么可疑的事情发生了。但看起来这可能是cin实现中的问题,而不是迭代器中的问题。

不幸的是,libc++中还有一个bug(除了ecatmur指出的那个bug之外)。修复方法如下:

Index: include/__std_stream
===================================================================
--- include/__std_stream    (revision 176092)
+++ include/__std_stream    (working copy)
@@ -150,7 +150,7 @@
     {
         for (int __i = __nread; __i > 0;)
         {
-            if (ungetc(__extbuf[--__i], __file_) == EOF)
+            if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
                 return traits_type::eof();
         }
     }

我会尽快办理。很抱歉出现了bug。谢谢你提醒我这件事。

修复提交的版本176822到libcxx public svn trunk。修复需要重新编译dylib,即使修复在头文件中。

我想你可能发现了一个已经修复的bug。这个提交(由@Howard Hinnant)包含以下更改:

@@ -104,7 +104,7 @@
     int __nread = _VSTD::max(1, __encoding_);
     for (int __i = 0; __i < __nread; ++__i)
     {
-        char __c = getc(__file_);
+        int __c = getc(__file_);
         if (__c == EOF)
             return traits_type::eof();
         __extbuf[__i] = static_cast<char>(__c);
@@ -131,7 +131,7 @@
                 if (__nread == sizeof(__extbuf))
                     return traits_type::eof();
                 {
-                    char __c = getc(__file_);
+                    int __c = getc(__file_);
                     if (__c == EOF)
                         return traits_type::eof();
                     __extbuf[__nread] = static_cast<char>(__c);

你会注意到旧版本将getc的返回值存储到char中,这是一个禁忌,因为它混淆了char的值0xffint的值EOF(即-1)。

该错误仅适用于cin,因为受影响的方法在__stdinbuf上,这是libc++仅用于实现cin的类型;ifstream例如使用basic_filebuf<char> .

检查系统上的libcxx/include/__std_stream文件,看看它是否有这个错误;如果有,应用补丁程序,它应该修复它。

迭代器正在从流中提取。
流需要以binary模式打开,以防止对原始数据的任何转换。

接下来,不要使用charchar类型可以是有符号的、无符号的,也可以是无符号的,这取决于编译器。我建议在读取二进制八位字节时使用uint8_t

试试这样写:

#include <cstdint>
using std::uint8_t;
istreambuf_iterator<uint8_t> eos;

相关内容

最新更新