提问人:AnT stands with Russia 提问时间:10/21/2014 最后编辑:AnT stands with Russia 更新时间:10/21/2014 访问量:177
用 setw 阅读:to eof or not to eof?
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 个字符;
- 文件结束发生在输入序列上;
- isspace(c,is.getloc()) 对于下一个可用的输入字符 c,为 true。
鉴于上述情况,我认为操作员没有任何理由将流驱动到上述代码中的状态。>>
eof
但是,这就是 GCC 库中的运算符实现的样子>>
...
__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
所以,我的问题是:在上述情况下触发流状态,就像 GCC 所做的那样 - 从标准的角度来看,它是否合法?我没有在文档中明确指定它。MSVC 和 GCC 的行为是否合规?还是他们中只有一个行为正确?eof
答:
该特定位的定义与 的设置无关,因为它仅描述操作何时终止,而不描述触发特定位的内容。operator>>
eofbit
标准(草案)中的描述说:eofbit
eofbit - 表示输入操作到达输入序列的末尾;
我想这里这取决于你想如何解释“达到”。请注意,gcc 实现没有正确设置 ,其定义为failbit
failbit - 指示输入操作无法读取预期的字符,或者 输出操作无法生成所需的字符。
所以我认为并不一定意味着文件的末尾阻碍了任何新字符的提取,只是文件的末尾已经“到达”。eofbit
我似乎找不到更准确的“达到”描述,所以我想这将是实现定义的。如果此逻辑正确,则 MSVC 和 gcc 行为都是正确的。
编辑:特别是,似乎设置了何时返回.本节和本节中对此进行了描述。所以现在的问题是:什么时候允许流的当前位置前进?eofbit
sgetc()
eof
istreambuf_iterator
basic_istream::sentry
最终编辑:事实证明,g++ 可能具有正确的行为。
每个字符扫描都会经过,以便解析不同的字符集、货币格式、时间描述和数字格式。虽然似乎没有关于字符串如何工作的通俗描述,但对数字、时间和金钱的函数应该如何运作有非常具体的描述。您可以从草稿的第 687 页找到它们。<locale>
operator>>
do_get
所有这些都是从读取(字符的“全局”版本,通过语言环境读取)开始的(对于数字,您可以在草稿的第 1018 页找到调用定义)。然后处理 ctype,最后推进迭代器。ctype
istreambuf_iterator
因此,一般来说,这要求内部迭代器始终指向最后一个字符之后的下一个字符;如果不是这种情况,理论上你可以提取比你想要的更多:
string str = "strin1";
istringstream is(str);
is >> setw(6) >> str;
int x;
is >> x;
如果提取 for 后的当前字符不在 上,则标准将要求获取值 1,因为对于数字提取,标准明确要求迭代器在第一次读取后前进。is
str
eof
x
由于这没有多大意义,并且鉴于标准中描述的所有复杂提取都以相同的方式运行,因此对于字符串,同样的情况也是有道理的。因此,由于读取 6 个字符后的指针落在 上,因此需要设置。is
eof
eofbit
评论
eof
eofbit
sgetc
eof
*it
eof
it
operator>>
n
eof
eofbit
评论
isspace
eofbit