views:

704

answers:

4

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  A: 

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.

dirkgently
Clarification: codepad C++ compilation uses g++ 4.1.2. I think Mac's istringstream is likely to have the same or a similar fmtflags (but different from VS2005).
dirkgently
Couldn't this just mean that the actual implementation values of fmtflags differ between the c++ implementations?
anon
Yes, it can. What is your take on the source of the error?
dirkgently
anon
Yes, I too have seen that it is locale dependent. Maybe tomorrow I will give this a try with a Mac proper!
dirkgently
@Neil: yes, it looks like gcc and VS have different implementation values for the fmtflags. I get the same results as dirkgently - 513 and 4098. Looking at the implementation the only flags set on both are dec and skipws.
Steve Folly
@Steve: If they have the same locale, then this is a bug with g++.
dirkgently
FWIW, I get the same g++ behaviour as in the question using MinGW 3.4.2 on windows
anon
Is this with std=c++98 and related switches on?
dirkgently
@dirkgently: both are using locale "C" (assuming std::locale().name() is the correct thing to do?). With due respect, why do you think g++ is wrong, and not VS?
Steve Folly
One of them is broken. The conversion looks legal.
dirkgently
Hmmmm. VS aligns closer to what you'd expect from implicit conversions, but then the stream conversion really does fail for n < "-65535" and > "65535". Aaargggh!!!
Steve Folly
+3  A: 
Max Lybbert
+1 for locality tidbit.
ceretullis
+2  A: 

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.

anon
THis reply on clc++m http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/97475b21515462c9/ce369a327fa39243#ce369a327fa39243 confirms that C++ input is defined interms of C input - but comes to a rather different conclusion!
anon
not sure i agree with that guy. strtoul says that the resulting value is negated. when 1 negated for unsigned short it is USHRT_MAX (modulo arithmetic), which is what MSVC returns correctly. Not sure why he says it should return 1 ?
Johannes Schaub - litb
No, I think he was a bit off-beam there. But what's your take on the original question?
anon
i'm going to agree with that dude on the usenet, apart from the last part as i stated :) (posted an answer on that thread. let's see when ops release it :)) anyway, i just checked with gcc4.4, and its op>> also returns USHRT_MAX. So i suspect that bug is already fixed :)
Johannes Schaub - litb
A: 

I'm having same issue in Ubuntu 10.04 using gcc4.4

#include <sstream>
#include <iostream>

int main() {
  std::stringstream myStream;

  myStream << "-123";

  unsigned int myUInt;
  myStream >> myUInt;

  if(myStream.fail()) {
    std::cout << "FAILED" << std::endl;
  }
}

doesn't give FAILED

Gaetano Mendola