8

次の (おもちゃの) プログラムは、libstdc++ と libc++ に対してリンクすると、異なるものを返します。これは libc++ のバグですか、それとも istream eof() の仕組みがわかりませんか? -std=c++0x の有無にかかわらず、Linux および mac os x で g++ を使用し、mac os x で clang を使用して実行しようとしました。(get() などによる) 読み取りの試行が実際に失敗するまで、eof() は true を返さないというのが私の印象でした。これは libstdc++ の動作ですが、libc++ の動作ではありません。

#include <iostream>
#include <sstream>

int main() {
    std::stringstream s;

    s << "a";

    std::cout << "EOF? " << (s.eof() ? "T" : "F") << std::endl;
    std::cout << "get: " << s.get() << std::endl;
    std::cout << "EOF? " << (s.eof() ? "T" : "F") << std::endl;

return 0;
}

Thor:~$ g++ test.cpp
Thor:~$ ./a.out
EOF? F
get: 97
EOF? F
Thor:~$ clang++ -std=c++0x -stdlib=libstdc++ test.cpp 
Thor:~$ ./a.out
EOF? F
get: 97
EOF? F
Thor:~$ clang++ -std=c++0x -stdlib=libc++ test.cpp 
Thor:~$ ./a.out
EOF? F
get: 97
EOF? T
Thor:~$ clang++ -stdlib=libc++ test.cpp 
Thor:~$ ./a.out
EOF? F
get: 97
EOF? T
4

4 に答える 4

5

編集:これは、古いバージョンのlibc++がC++標準を解釈する方法が原因でした。解釈はLWG問題2036で議論され、それは正しくないと判断され、libc++が変更されました。

現在のlibc++は、テストでlibstdc++と同じ結果をもたらします。

古い答え:

あなたの理解は正しいです。

istream::get()次のことを行います。

  1. を呼び出しgood()failbitfalseを返す場合は設定します(これにより、他のビットが設定されたストリームにフェイルビットが追加されます)、(§27.7.2.1.2[istream::sentry]/2
  2. 必要に応じて、tie()されたものをすべてフラッシュします
  3. good()この時点でfalseの場合、eofを返し、他には何もしません。
  4. または()を呼び出すかのように文字抽出しますrdbuf()->sbumpc()rdbuf()->sgetc()§27.7.2.1[istream]/2
  5. sbumpc()またはsgetc()返されたeofの場合、を設定しますeofbit。(§27.7.2.1[istream]/3)とfailbit§27.7.2.2.3[istream.unformatted]/4
  6. 例外がスローされた場合は、badbit(§27.7.2.2.3[istream.unformatted]/1)を設定し、許可されている場合は再スローします。
  7. gcountを更新し、文字(または、取得できなかった場合はeof)を返します。

(C ++ 11から引用された章ですが、§27.6。*の下でC ++ 03にはすべて同じルールがあります)

次に、実装を見てみましょう。

libc ++(現在のsvnバージョン)は、get()の関連部分を次のように定義しています。

sentry __s(*this, true);
if (__s)
{
    __r = this->rdbuf()->sbumpc();
    if (traits_type::eq_int_type(__r, traits_type::eof()))
       this->setstate(ios_base::failbit | ios_base::eofbit);
    else
        __gc_ = 1;
}

libstdc ++(gcc 4.6.2に付属)は、と同じ部分を定義します

sentry __cerb(*this, true);
if (__cerb)
  {
    __try
      {
        __c = this->rdbuf()->sbumpc();
        // 27.6.1.1 paragraph 3
        if (!traits_type::eq_int_type(__c, __eof))
          _M_gcount = 1;
        else
          __err |= ios_base::eofbit;
      }
[...]
if (!_M_gcount)
  __err |= ios_base::failbit;

sbumpc()ご覧のとおり、sbumpc()がeofを返した場合にのみ、両方のライブラリがeofbitを呼び出して設定します。

テストケースは、両方のライブラリの最近のバージョンを使用して、同じ出力を生成します。

于 2012-01-25T18:03:37.047 に答える
4

これはlibc++のバグであり、Cubbiが指摘したように修正されました。私の悪い。詳細はこちら:

http://lwg.github.io/issues/lwg-closed.html#2036

于 2012-01-26T15:14:10.433 に答える
1

の値はs.eof()2 番目の呼び出しでは指定されていません。これは true または false である可能性があり、一貫していない可能性さえあります。あなたが言えることは、s.eof()true を返す場合、今後のすべての入力が失敗するということだけです (ただし、false を返す場合、将来の入力が成功するという保証はありません)。失敗 ( s.fail()) の後、 s.eof()true が返された場合、ファイルの終わりが原因で失敗した可能性があります (ただし、100% 確実ではありません)。ただし、次のシナリオを検討する価値があります。

double test;
std::istringstream s1("");
s1 >> test;
std::cout << (s1.fail() ? "T" : "F") << (s1.eof() ? "T" : "F") << endl;
std::istringstream s2("1.e-");
s2 >> test;
std::cout << (s2.fail() ? "T" : "F") << (s2.eof() ? "T" : "F") << endl;

"TT"私のマシンでは、最初の行はデータがなかった (ファイルの終わり) ために失敗し、2 番目の行は浮動小数点値が正しくフォーマットされていなかったために失敗したにもかかわらず、両方の行が.

于 2012-01-25T15:27:48.740 に答える
0

ファイルの終わりを超えて読み取ろうとする操作がある場合、eofbit が設定されます。成功する整数の)。IE FT を取得して期待する

#include <iostream>
#include <sstream>

int main() {
    std::stringstream s("12");
    int i;
    s >> i;

    std::cout << (s.fail() ? "T" : "F") << (s.eof() ? "T" : "F") << std::endl;

    return 0;
}

ここでは、返された文字の後に istream::get が試行して読み取ることを期待していません (つまり、\n を読み取った場合、次の行に入るまでハングしないとは思いません)。したがって、libstd++ は確かに正しいようです。少なくともQOI POVで。

istream::get の標準的な説明は、方法を説明せずに「文字 c があればそれを抽出する」とだけ述べているため、libc++ の動作を妨げるようには見えません。

于 2012-01-25T15:27:40.643 に答える