I was a bit tired when I wrote that post, and made a number of mistakes
which I'm now correcting:
On 03/09/2018 03:06 PM, James Kuyper wrote:
> On 03/09/2018 12:51 PM, Bob Langelaan wrote:
>> If you have code such as:
>>
>> int var;
>> cin >> var;
>>
>> and the user inputs:
>>
>> 12345i
>>
>> afterward, with MS VS, var will contain 12345 and the character 'i' remains in the cin buffer. No error flags will be raised for the cin object.
>>
>> With some other compilers, including Xcode and Clion , var will contain the value 0 after the operation and the 'i' will have been swallowed up in the operation as well. In other words, the 'i' will no longer be in the cin buffer. Not sure about the error state of the cin object after the operation.
>>
>> Does the C++ language specify what the result should be? Could both results be "correct"?
>
> Yes, though figuring out what the specification means gets complicated.
I just realized that you asked two questions, and my "Yes" applied only
to the first one. The answer to the second question is implied by the
rest of my response - it's "No".
...
The following citations from section 22 are actually from section 25:
> 22.2 specifies that std::use_facet<Facet>() returns a Facet&
>
> 22.4.2.1.1 specifies that std::num_get::get(in, end, str, err, val)
> calls do_get(in, end, str, err, val), which is a virtual function.
>
> 22.4.2.1.2 specifies that std::num_get::do_get(in, end, str, err, val)
> reads in characters from the string, converting the locale-specific
> decimal_point character to '.', discarding characters prior to the
> decimal point which match the locale-specific thousands_sep(), and
> converting any other characters that cannot be found in the string
> "0123456789abcdefxABCDEFX+-" to null characters, and stopping as soon as
> a character is found which is not allowed by the conversion specifier.
> Note that 'i' is not allowed by any of the conversion specifiers, so it
> is permitted only when using a locale which specifies 'i' as the
> thousands separator :-).
At this point, you might be asking "what conversion specifier?", since I
dropped the paragraph explaining that point. 22.4.2.1.2p3 describes the
behavior in terms of the following example code:
fmtflags flags = str.flags();
fmtflags basefield = (flags & ios_base::basefield);
fmtflags uppercase = (flags & ios_base::uppercase);
Tables 73 specifies the corresponding <cstdio> scanf() conversion
specifier: if basefield is oct, hex, or 0, then the specifier is "%o",
"%X", or "%i" respectively. The only other valid value for basefield is
dec, in which case the fact that var is signed means that the specifier
is "%d". do_get() is not actually defined as calling scanf(). Instead:
> do_get() then passes the character string to the C standard library
> function strtoll(). At this point, you have to switch standards to get a
> complete description of the process, but you don't need that much detail
> for this question. For this input, strtoll() should set lval to 12345.
scanf() and num_get::do_get() are both described as calling strtoll() -
the conversion specifiers determine which base scanf() passes to
strtoll(): 8, 16, 0, and 10 for the specifiers mentioned above, in that
order. The implication of table 73 is that do_get() must do the same.