代码之家  ›  专栏  ›  技术社区  ›  Steve Folly

字符串流无符号转换中断?

  •  4
  • Steve Folly  · 技术社区  · 17 年前

    考虑这个程序:

    #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股份有限公司版本5490)上尝试过这个,断言是真的;它无法将-1转换为无符号short。

    然而,在Visual Studio 2005(和2008)中,断言失败,n的结果值与编译器生成的隐式转换的预期值相同,即“-1”是65535,“-2”是65534,以此类推。但当“-32769”转换为32767时,它就变得奇怪了。

    3 回复  |  直到 17 年前
        1
  •  5
  •   anon    17 年前

    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;
        }
    }
    

        2
  •  3
  •   Max Lybbert    17 年前

    Your default standard is the "classic" C locale :

    到目前为止,主要使用 区域设置 输入流 奥斯特雷姆 区域设置 默认情况下,流的全局 区域设置 在流创建时(第6页)。 ...

    区域设置::classic() (第11页)。

    根据GCC的说法, numeric overflow is allowed to fail the stream input operation (谈论溢出带符号整数的负数):

    多亏了另一个答案, a bug was filed and this behavior changed :

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

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

    其次,尽管整数溢出通常是可预测的,但我相信 officially undefined behavior ,所以虽然我不能说为什么-32769“转换为32767,但我认为这是允许的。

        3
  •  1
  •   dirkgently    17 年前

    #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;
    }
    

    flags: 513
    

    codepad.org (我认为使用g++)这给出了:

    flags: 4098
    

    这告诉我gcc使用不同的默认值 fmtflags 控制可能的转换,你会得到不同的结果。