请考虑以下示例代码:
#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;
}
包含以下内容的输入文件:“foo \ xffbar”:
$ 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 ++中的错误吗?我的谷歌搜索现有的错误没有任何结果。
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实现中的一个问题,而不是迭代器。
答案 0 :(得分:5)
不幸的是,libc ++中仍然存在一个错误(除了指出的一个ecatmur)。这是修复:
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,即使修复程序位于标题中。
答案 1 :(得分:2)
我想你可能已经发现了一个已经修复过的bug。 This commit(按@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
值{{ 1}} 0xff
值int
(即EOF
)。
该错误仅适用于-1
,因为受影响的方法位于cin
,这是libc ++仅用于实现__stdinbuf
的类型; cin
例如{}使用ifstream
。
检查系统上的basic_filebuf<char>
文件,看看它是否有此错误;如果是的话,应用补丁,它应该修复它。
答案 2 :(得分:1)
迭代器从流中提取
需要使用binary
模式打开流,以防止对原始数据进行任何转换。
接下来,请勿使用char
。 char
类型可以是有符号的,也可以是无符号的,具体取决于编译器。我建议在读取二进制八位字节时使用uint8_t
。
尝试这样的事情:
#include <cstdint>
using std::uint8_t;
istreambuf_iterator<uint8_t> eos;