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