2012-01-25 47 views
8

下面的(玩具)程序在鏈接到libstdC++和libC++時返回不同的東西。這是libC++中的錯誤還是我不明白istream eof()的工作原理?我已經嘗試在Linux和Mac OS X上使用g ++運行它,在mac os x上使用和不使用-std = C++ 0x。我的印象是,直到試圖讀取(通過get()或其他)實際上失敗後,eof()纔會返回true。這是libstdC++的行爲方式,但不是libC++的行爲方式。istream eof libC++和libstdC++之間的差異

#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 

回答

0

eofbit設置時,有哪些嘗試讀取過去的文件的末尾的操作時,操作可能不會失敗(如果您正在閱讀的整數且有整數後沒有行結束,我期待eofbit被設置,但整數讀取成功)。 I.E.我得到並期待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 ::得到嘗試和返回的字符之後讀(即我不希望它掛起,直到我進入下一行,如果我讀一個\ n與它),所以libstd ++似乎確實是正確的,至少在QOI POV。

istream :: get的標準描述只是說「提取一個字符c,如果有的話」而不描述如何,所以似乎不會阻止libC++的行爲。

1

s.eof()的值在第二個呼叫—中未指定,它可能是 是真或假,甚至可能不一致。所有你可以說的是 ,如果s.eof()返回true,所有未來的輸入將失敗(但如果它 返回false,不能保證未來的輸入將成功)。 失敗後(s.fail()),如果s.eof()返回true,則很可能(但不是 )確定失敗是由於文件結束導致的。這是值得 考慮以下情形,但是:

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",儘管第一 失敗,因爲沒有數據(文件結束),第二是因爲 浮點值的格式不正確。

+0

它是如何未指定的?標準很明確:如果sbumpc()/ sgetc()返回eof,則設置failbit和eofbit,如果拋出異常則設置badbit。 – Cubbi

+0

@Cubbi No.如果'sgetc'返回eof,但不一定'failbit',則設置'eofbit';展望未來總是合法的,有時是必要的。何時以及何時經常發生'get'調用'sgetc'沒有被指定。 –

+0

我發佈了答案作爲答案。 – Cubbi

5

編輯:這是由於老版本的libC++解釋C++標準。解釋在LWG issue 2036中討論過,它被認爲是不正確的,libC++被改變了。

當前的libC++在測試中給出了與libstdC++相同的結果。

老回答:

你的理解是正確的。

istream::get()執行以下操作:

  1. 呼叫good(),並設置failbit如果返回false(這增加了failbit到了一些其他位設置流),(§27.7.2.1.2[istream::sentry]/2
  2. 刷新任何的領帶()'必要時
  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,但C++ 03都具有相同的規則,在§27.6引述章節。*)

現在讓我們來看看實現:

的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)定義相同的部分,

相關的部分

如您所見,兩個庫都調用sbumpc()並且當且僅當sbumpc()返回eof時才設置eofbit。

您的測試用例爲我使用兩個庫的最新版本生成相同的輸出。

+0

這是奇怪的。我在標準版(C++ 03和N3291)的 版本中找不到任何引用的文本:我的兩個版本都說'get' 「表現爲無格式輸入功能。 構建了一個哨兵對象,提取一個字符c,如果有一個是可用的 。「對'rdbuf() - > sbump()'或 'rdbuf() - > sgetc()'的調用次數沒有任何影響。雖然我通常不會期望它,但有 沒有什麼是不合法的,因爲執行時會額外調用 'rdbuf() - > sgetc()',並因此設置'eofbit'。 –

+0

你的動作列表中的幾點:關於點2: 'istream :: get()'不這樣做---它是'sentry'對象的構造函數 的一部分動作。關於第3點和第4點: 標準的約束要少得多。由於'rdbuf() - > sgetc()'不會調用'rdbuf() - > sbumpc()'或'rdbuf() - > sgetc()',這是一個錯誤, 提取和'rdbuf() - > snextc()'和 'rdbuf-> sgetn()',這些都沒有提及)。這並沒有說什麼關於 何時和如果預見發生。 –

+0

@JamesKanze關於哨兵,其構造函數的動作是'istream :: get()'的一部分。就像C++中的任何東西一樣,它就像是:實現可能(有時也會)直接在get()中執行一些操作。關於對sgetc的額外調用 - 在調用它或任何其他函數時沒有任何違法行爲,但是由於它返回的內容而設置eofbit是非法的,因爲它違反了假定條款。 – Cubbi