stringstream unsigned conversion broken?

流过昼夜 提交于 2019-12-01 21:03:03

问题


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??)


回答1:


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.




回答2:


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.




回答3:


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.



来源:https://stackoverflow.com/questions/786951/stringstream-unsigned-conversion-broken

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!