I think that both are wrong in C++171 and that the expected output should be:
4294967295 0
While the returned value is correct for the latest versions of both compilers, I think that the ios_base::failbit
should be set, but I also think there is a confusion about the notion of field to be converted in the standard which may account for the current behaviors.
The standard says — [facet.num.get.virtuals#3.3]:
The sequence of chars accumulated in stage 2 (the field) is converted to a numeric value by the rules of one of the functions declared in the header <cstdlib>
:
For a signed integer value, the function strtoll
.
For an unsigned integer value, the function strtoull
.
For a floating-point value, the function strtold
.
So we fall back to std::strtoull
, which must return2 ULLONG_MAX
and not set errno
in this case (which is what both compilers do).
But in the same block (emphasis is mine):
The numeric value to be stored can be one of:
zero, if the conversion function does not convert the entire field.
the most positive (or negative) representable value, if the field to be converted to a signed integer type represents a value too large positive (or negative) to be represented in val
.
the most positive representable value, if the field to be converted to an unsigned integer type represents a value that cannot be represented in val
.
the converted value, otherwise.
The resultant numeric value is stored in val
. If the conversion function does not convert the entire field, or if the field represents a value outside the range of representable values, ios_base::failbit
is assigned to err
.
Notice that all these talks about the "field to be converted" and not the actual value returned by std::strtoull
. The field here is actually the widened sequence of character '-', '1'
.
Since the field represents a value (-1) that cannot be represented by an unsigned
, the returned value should be UINT_MAX
and the failbit should be set on std::cin
.
1clang
was actually right prior to C++17 because the third bullet in the above quote was:
- 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
.
2 std::strtoull
returns ULLONG_MAX
because (thanks @NathanOliver) — C/7.22.1.4.5:
If the subject sequence has the expected form and the value of base is zero, the sequence of characters starting with the first digit is interpreted as an integer constant according to the rules of 6.4.4.1.
[...]
If the subject sequence begins with a minus sign, the value resulting from the conversion is negated (in the return type).