stringstream 无符号转换损坏?

发布于 2024-07-17 06:01:37 字数 656 浏览 16 评论 0 原文

考虑这个程序:

#include <iostream>
#include <string>
#include <sstream>
#include <cassert>

int main()
{
    std::istringstream stream( "-1" );
    unsigned short n = 0;
    stream >> n;
    assert( stream.fail() && n == 0 );
    std::cout << "can't convert -1 to unsigned short" << std::endl;
    return 0;
}

我在 OS X 10.5.6 上的 gcc(版本 4.0.1 Apple Inc. build 5490)上尝试过这个程序,断言是正确的; 它无法将 -1 转换为无符号短整型。

然而,在 Visual Studio 2005(和 2008)中,断言失败,n 的结果值与编译器生成的隐式转换所期望的值相同 - 即“-1”是 65535,“-2”是 65534 等但随后“-32769”转换为 32767 就变得很奇怪。

这里谁是对的,谁是错的? (-32769 到底是怎么回事??)

Consider this program:

#include <iostream>
#include <string>
#include <sstream>
#include <cassert>

int main()
{
    std::istringstream stream( "-1" );
    unsigned short n = 0;
    stream >> n;
    assert( stream.fail() && n == 0 );
    std::cout << "can't convert -1 to unsigned short" << std::endl;
    return 0;
}

I tried this on gcc (version 4.0.1 Apple Inc. build 5490) on OS X 10.5.6 and the assertion is true; it fails to convert -1 to an unsigned short.

In Visual Studio 2005 (and 2008) however, the assertion fails and the resulting value of n is the same as what you would expect from an compiler generated implicit conversion - i.e "-1" is 65535, "-2" is 65534, etc. But then it gets weird at "-32769" which converts to 32767.

Who's right and who's wrong here? (And what the hell's going on with -32769??)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一刻暧昧 2024-07-24 06:01:37

GCC 在 Max Lybbert 的帖子中声称的行为基于 C++ 标准中的表格,这些表格将 iostream 行为映射到 printf/scanf 转换器(或者至少是我读到的)。 然而,g++的scanf行为似乎与istream行为不同:

#include <iostream>
#include <cstdio>
using namespace std;;

int main()
{
    unsigned short n = 0;
    if ( ! sscanf( "-1", "%hu", &n ) ) {
        cout << "conversion failed\n";
    }
    else {
        cout << n << endl;
    }
}

实际上打印65535。

The behaviour claimed by GCC in Max Lybbert's post is based on the tables om the C++ Standard that map iostream behaviour onto printf/scanf converters (or at least that;'s my reading). However, the scanf behaviour of g++ seems to be different from the istream behavior:

#include <iostream>
#include <cstdio>
using namespace std;;

int main()
{
    unsigned short n = 0;
    if ( ! sscanf( "-1", "%hu", &n ) ) {
        cout << "conversion failed\n";
    }
    else {
        cout << n << endl;
    }
}

actually prints 65535.

夜清冷一曲。 2024-07-24 06:01:37

首先,将字符串“-1”读取为负数取决于区域设置(区域设置可以通过将负数括在括号中来识别负数)。 您的默认标准是“经典”C 语言环境

到目前为止,区域设置的主要用途是在流 I/O 中隐式使用。 每个istreamostream都有自己的区域设置。 默认情况下,流的区域设置是创建流时的全局区域(第6页)。 ...

最初,全局语言环境是标准 C 语言环境,locale::classic()(第 11 页)。

根据 GCC 人员的说法,允许数字溢出流输入操作失败(谈论溢出有符号整数的负数):


[T]libstdc++-v3 的行为严格符合标准。 ...当尝试读取时,它适合有符号的 int i,并且失败。

感谢另一个答案,已提交错误并且此行为已更改

哎呀,显然我们从未正确解析无符号负值。 这
修复很简单。 ...

已在主线中修复,也将在 4.4.1 中修复。

其次,虽然整数溢出通常是可以预测的,但我相信它是 官方未定义的行为,所以虽然我不能说出为什么 -32769” 转换为 32767,但我认为这是允许的。

First, reading the string "-1" as a negative number is locale dependent (it would be possible for a locale to identify negative numbers by enclosing them in parenthesis). Your default standard is the "classic" C locale:

By far the dominant use of locales is implicitly, in stream I/O. Each istream and ostream has its own locale. The locale of a stream is by default the global locale at the time of the stream’s creation (page 6). ...

Initially, the global locale is the standard C locale, locale::classic() (page 11).

According to the GCC guys, numeric overflow is allowed to fail the stream input operation (talking about negative numbers that overflowed a signed int):

[T]he behaviour of libstdc++-v3 is strictly standard conforming. ... When the read is attempted it does not fit in a signed int i, and it fails.

Thanks to another answer, a bug was filed and this behavior changed:

Oops, apparently we never parsed correctly negative values for unsigned. The
fix is simple. ...

Fixed in mainline, will be fixed in 4.4.1 too.

Second, although integer overflow is generally predictable, I believe it's officially undefined behavior, so while I can't say why -32769" converts to 32767, I think it's allowed.

爱的故事 2024-07-24 06:01:37

试试这个代码:

#include <iostream>
#include <string>
#include <sstream>
#include <cassert>

int main()
{
    std::istringstream stream( "-1" );
    std::cout << "flags: " << (unsigned long)stream.flags() << std::endl;
    return 0;
}

我在我的 VS2005 上尝试过这个:

flags: 513

codepad.org (我认为它使用 g++)上给出:

flags: 4098

这告诉我 gcc 使用不同的默认 fmtflags。 由于 fmtflags 控制可能的转换,因此您会得到不同的结果。

Try this code:

#include <iostream>
#include <string>
#include <sstream>
#include <cassert>

int main()
{
    std::istringstream stream( "-1" );
    std::cout << "flags: " << (unsigned long)stream.flags() << std::endl;
    return 0;
}

I tried this on my VS2005:

flags: 513

and on codepad.org (which I think uses g++) this gives:

flags: 4098

This tells me that gcc uses a different default fmtflags. Since fmtflags control what conversions are possible you are getting different results.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文