g++ and clang++ different behaviour with stream input and unsigned integer
Asked Answered
T

1

19

I came across a difference in behavior, between gcc (4.9.2) and clang (3.5.0), which surprised me.

When I try to feed an unsigned int from an std::istringstream initialized with a negative value ("-15", in the example) I get

  • an error (with fail() bit raised) with clang++
  • the initialization with signed(-15) with gcc++

I prepared the trivial following example program.

#include <sstream>
#include <iostream>

int main ()
 {
   std::istringstream iss("-15");

   unsigned int  ui;

   iss >> ui;

   std::cout << "ui[" << ui << "] signed(ui)[" << signed(ui)
      << "] flags[" << iss.fail() << iss.good() << iss.bad()
      << iss.eof() << "]\n";

   return 0;
 }

With clang++, I obtain the following output

ui[0] signed(ui)[0] flags[1001]

With g++, I obtain the following output

ui[4294967281] signed(ui)[-15] flags[0001]

I have two questions.

The first is obvious: who's right? clang++, g++ or is an undefined behaviour?

The second is: how can I force the gcc++ to behave like the clang++, giving an error when extracting an unsigned value from a string beginning with a minus?

Thanks and sorry for my bad english.

EDIT 2016.04.03

I realized that this isn't a difference between g++ and clang++, but a difference between libstd++ and libc++.

Compiling and linking with clang++ and libstd++, I obtain the same output I get with g++.

Sorry.

Tannenbaum answered 2/4, 2016 at 19:31 Comment(13)
Which version of gcc / clang are you using? I get the same result on Windows with g++ 5.1.0 and clang 3.7.0 (same as your g++ output).Thrash
g++ 4.9.2 and clang++ 3.5.0 on a debian 8.0 ("Jessie") amd64Tannenbaum
As far as I understand the standard, the behavior should be the same as using std::stroull, which should behave as g++ did for you (but I found the C standard a bit fuzzy about this behavior... ).Thrash
The C99 standard does say that strtoull negates its result in the return type . However the C++ standard also says that this extraction may yield "[...] zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err." and it is not clear whether "represented in" an unsigned int also allows the usual signed-unsigned conversion. (But if it does then it is unclear in what situations this failure zero would be returned)Tem
To work around this problem you could get a character, and if it is - take whatever error handling action; or if it is not - then put it back and do the extractionTem
Duplicate, although the explanation in the answer is unconvincing (it basically says "it's unclear")Tem
So it would seem correct the behavior of g++ and wrong the clang++ one; I would lean on the contrary. About the idea to test to see if the first character is a "-" ... yes ... I had thought about it but I'm trying to implement the solution in a template method. The ideal would be a way that does not hamper with signed types or even with non-numeric types. Anyway, thank you Holt and thank you M.MTannenbaum
This has been reported as a libstdc++ bug but I haven't confirmed it yet, for the same reasons given above (it's unclear).Littles
I'd suggest either deleting this question, or writing the answer yourself and accepting it, @max66.Altar
@ Jonathan Wakely: sorry, I'm not sure I understand (I'm in big troubles with English). You think that the current behaviour of libstdc++ is the correct one and that the reported bug isn't a bug?Tannenbaum
@TriskalJM: for now I'm embarrassed to do so. If I understand correctly, it seems that the correct behavior is that of libstdc++ and it's the libc++ to make mistakes. But also that it is not clear at all. I think I'll wait a few more days and then I'll try to do what you suggest.Tannenbaum
@TriskalJM: There doesn't seem to be any reason for max66 to do either of those things. It's a good question and certainly shouldn't be deleted.Roddie
@max66: To clarify Jonathan Wakely's comment: he is the maintainer of libstdc++. He says the correct behavior is unclear (ie he doesn't know which is right either).Roddie
M
1

This has been discussed before here: Negative numeric string (e.g. "-10") to unsigned short

The answer is that according to the C++ standard 22.4.2.1.2p3, the conversion is required to fail and the value stores should be:

the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.

Therefore, clang++ is the correct behavior.

Menes answered 26/8, 2016 at 6:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.