5

次のサンプルコードについて考えてみます。

#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

ここで、clanglibc++とgnulibstdc++を使用したテストについて説明します。

$ 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の実装に問題があるようです。

4

3 に答える 3

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();
         }
     }

これをできるだけ早くチェックインします。バグでごめんなさい。私の注意を引いてくれてありがとう。

コミットされたリビジョン176822をlibcxxpublicsvnトランクに修正します。修正がヘッダーにある場合でも、修正には再コンパイルされたdylibが必要です。

于 2013-03-11T19:45:46.943 に答える
2

すでに修正されているバグを見つけたかもしれません。 このコミット@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混同するという正確な理由から、no-noです。char0xffintEOF-1

cinこのバグは、影響を受けるメソッドがオンになっているためにのみ適用されます__stdinbuf。これは、libc++が実装にcinのみ使用するタイプです。ifstream例:を使用しbasic_filebuf<char>ます。

システム上のファイルをチェックしlibcxx/include/__std_streamて、このバグがあるかどうかを確認します。含まれている場合は、パッチを適用すると修正されます。

于 2013-03-11T19:12:21.217 に答える
1

イテレータはストリームから抽出しています。元のデータへの変換を防ぐために、
ストリームをモードで開く必要があります。binary

次に、を使用しないでくださいcharchar型は、コンパイラーに応じて、符号付き、符号なし、または符号なしのいずれかになります。uint8_tバイナリオクテットを読み取るときに 使用することをお勧めします。

次のようなものを試してください。

#include <cstdint>
using std::uint8_t;
istreambuf_iterator<uint8_t> eos;
于 2013-03-11T17:31:20.373 に答える