使用 std::istream::operator>>处理无符号类型时,如何区分失败的提取和下溢?

With std::istream::operator>> working on unsigned types, how do I tell apart a failed extraction from an underflow?

提问人:m88 提问时间:9/9/2019 最后编辑:xskxzrm88 更新时间:9/10/2019 访问量:220

问:

我想使用 std::istream::operator>> 将数据提取到无符号类型中(在模板中,因此它可以是 ushort、uint 等)。具体来说,我正在使用 std::stringstream 来解析从带有 std::getline() 调用的文件中提取的 std::string 行。

由于我正在从文件中读取,因此这些提取可能会因不同的原因而失败:下溢、溢出和“错误提取”。此类案件由STL处理:

如果提取失败,则将零写入值并设置 failbit。如果提取导致值过大或过小而无法容纳值,则写入 std::numeric_limits::max() 或 std::numeric_limits::min() 并设置 failbit 标志。

来源: cppreference

问题:对于无符号类型,std::numeric_limits::min() 等于 0,因此无法知道我是否正在读取不是整数的内容(在这种情况下,我正在中止程序)或者它是否只是一个下溢(在这种情况下,我只是限制值并发出警告)。

如何在不使用我正在使用的无符号类型的更大和/或有符号的等效项的情况下解决此问题?

C++ IO IO流

评论

0赞 nada 9/9/2019
我敢打赌,您的问题实际上是不同的:如何序列化/反序列化用户定义的数据。我说得对吗?
3赞 Frodyne 9/9/2019
我认为可悲的答案是,只是不提供您想要的错误消息粒度。我可以看到两种方法:1)读入有符号的长整型(或其他更大的数据类型),使用额外的空间来检查是否需要夹紧,然后将所有提取错误视为“错误输入:中止”。2)编写您自己的“从字符流中读取值”函数,并根据需要/想要尽可能细粒度地报告错误。std::istream::operator>>
0赞 m88 9/9/2019
@nada 是的,这是一个解串器。我正在测试边缘情况(用户将 int 文件馈送到未签名的 int 反序列化程序,这应该只会引发下溢警告)并注意到这个问题。

答:

1赞 xskxzr 9/10/2019 #1

无符号类型不会下溢。如果输入负数来表示“下溢”,则标准流不会将其视为错误。负数被换行到无符号类型中,并且未设置。failbit

因此,如果您看到 0 已存储并已设置,则可以断言这是提取失败。要检测负数错误,您必须做一些额外的工作。例如,可以首先读取(足够大的)有符号整数类型的值,以检测它是否为负数。failbit

评论

0赞 m88 9/10/2019
事实上,我做了一些研究,似乎 std::strtoull() 正如您所描述的那样工作。引用:“如果减号是输入序列的一部分,则从数字序列计算出的数值将被否定,就像结果类型中的一元减号一样,这应用了无符号整数环绕规则”。由于 istream::operator>> 是(间接)基于它的,因此有理由认为它以相同的方式工作。