[英]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.