[英]Reading with setw: to eof or not to eof?
請考慮以下簡單示例
#include <string>
#include <sstream>
#include <iomanip>
using namespace std;
int main() {
string str = "string";
istringstream is(str);
is >> setw(6) >> str;
return is.eof();
}
乍一看,由於顯式寬度由setw
操縱器指定,我希望>>
操作符在從輸入流成功提取所請求的字符數后完成讀取字符串。 我沒有看到它立即嘗試提取第七個字符的原因,這意味着我不希望流進入eof
狀態。
當我在MSVC ++下運行這個例子時,它按照我的預期工作:讀取后流保持良好狀態。 但是,在GCC中,行為是不同的:流最終處於eof
狀態。
語言標准,它為此版本的>>
運算符提供以下完成條件列表
- 存儲n個字符;
- 文件結束發生在輸入序列上;
- 對於下一個可用的輸入字符c,isspace(c,is.getloc())為true。
鑒於上述情況,我沒有看到>>
運算符在上述代碼中將流驅動到eof
狀態的任何原因。
...
__int_type __c = __in.rdbuf()->sgetc();
while (__extracted < __n
&& !_Traits::eq_int_type(__c, __eof)
&& !__ct.is(__ctype_base::space,
_Traits::to_char_type(__c)))
{
if (__len == sizeof(__buf) / sizeof(_CharT))
{
__str.append(__buf, sizeof(__buf) / sizeof(_CharT));
__len = 0;
}
__buf[__len++] = _Traits::to_char_type(__c);
++__extracted;
__c = __in.rdbuf()->snextc();
}
__str.append(__buf, __len);
if (_Traits::eq_int_type(__c, __eof))
__err |= __ios_base::eofbit;
__in.width(0);
...
如您所見,在每次成功迭代結束時,它會嘗試為下一次迭代准備下一個__c
字符,即使下一次迭代可能永遠不會發生。 在循環之后,它分析該__c
字符的最后一個值並相應地設置eofbit
。
所以,我的問題是:在上述情況下觸發eof
流狀態,就像GCC那樣 - 從標准的角度來看它是合法的嗎? 我沒有在文檔中明確指出它。 MSVC和GCC的行為是否合規? 或者只是其中一個表現正常?
該特定operator>>
的定義與eofbit
的設置無關,因為它僅描述操作何時終止,而不描述觸發特定位的內容。
標准(草案)中eofbit
的描述說:
eofbit - 表示輸入操作到達輸入序列的末尾;
我想在這里取決於你想要解釋“達到”的方式。 請注意,gcc實現正確無法設置failbit
,其定義為
failbit - 表示輸入操作無法讀取預期的字符,或者輸出操作無法生成所需的字符。
所以我認為eofbit
並不一定意味着文件的結尾阻礙了任何新字符的提取,只是文件的結尾已經“到達”了。
我似乎無法找到更准確的“達到”描述,所以我想這將是實現定義。 如果此邏輯正確,則MSVC和gcc行為都是正確的。
編輯:特別是,當sgetc()
返回eof
時,似乎eofbit
被設置。 這在istreambuf_iterator
部分和basic_istream::sentry
部分中都有描述。 所以現在問題是:什么時候流的當前位置允許前進?
最終編輯:事實證明,g ++可能具有正確的行為。
每個字符掃描都通過<locale>
,以允許解析不同的字符集,貨幣格式,時間描述和數字格式。 雖然似乎沒有關於operator>>
如何為字符串工作的直通描述,但是有關於數字,時間和金錢的do_get
函數應如何do_get
非常具體的描述。 您可以從草案的第687頁找到它們。
所有這些都是從istreambuf_iterator
讀取ctype
(字符的“全局”版本,通過locales讀取)開始的(對於數字,您可以在草稿的第1018頁找到調用定義)。 然后處理ctype,最后迭代器被提前。
因此,一般來說,這需要內部迭代器始終指向最后一個讀取后的下一個字符; 如果不是這樣的話你理論上可以提取超出你想要的東西:
string str = "strin1";
istringstream is(str);
is >> setw(6) >> str;
int x;
is >> x;
如果當前字符is
后提取str
並不在eof
,那么標准就需要x
得到值1,因為對於數字提取標准明確要求迭代器第一次讀取后前進。
由於這沒有多大意義,並且鑒於標准中描述的所有復雜提取都以相同的方式運行,因此對於字符串來說同樣會發生這種情況是有意義的。 因此,當指針為is
讀取6個字符之后落在eof
時, eofbit
需要被設置。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.