I'm trying to read a double, followed by a character, from cin using the snippet:
double d;
char c;
while(1) {
cin >> d >> c;
cout << d << c << endl;
}
The peculiar thing is that it works for some characters, but not for others. For example, it works for "2g", "2h", but fails for "2a", "2b", "2x" ...:
mwmbp:ppcpp mwisse$ ./a.out
2a
0
2b
0
2c
0
2g
2g
2h
2h
2i
0h
2x
0h
2z
2z
As pointed out by one of you, it does indeed work for integers. Do you know why it doesn't work for doubles? I have as yet been unable to find information on how cin interprets its input.
This is currently a bug on LLVM: https://llvm.org/bugs/show_bug.cgi?id=17782 Way back in 2014 it was assigned from Howard Hinnant to Marshall Clow since then... Well don't hold you breath on this getting fixed any time soon.
EDIT:
The istream
extraction operator internally uses num_get::do_get
Which sequentially performs these tasks for a double
:
- Selects a conversion specifier, for
double
that's%lg
- Tests for an empty input stream
- Checks if the next character in the string is contained in the
ctype
ornumpunct
facet
s - If
scanf
would allow the character obtained from 3 to be appended to the input field given the conversion specifier obtained in 1, if so 3 is repeated if not 5 is performed on the input field without this character - The
double
from the accepted input field is read in with - If 5 fails
failbit
is assigned to theistream
'siostate
, but if 5 succeeded, the result is assigned to thedouble
- If any thousands separators were allowed into the input field by
facet numpunct
in 3 their position is evaluated, if any of them violate thegrouping
rules of thefacet
,failbit
is assigned to theistream
'siostate
- If the input field used in 5 was empty
eofbit
is assigned to theistream
'siostate
That's a lot to say that for a double
you're really concerned with scanf
's %lg
conversion specifier's rules for extraction of a double
(which internally will depend upon strtof
's constraints):
- An optional plus or minus character
- One of the following
- "INF" or "INFINITY" (case insensitive)
- "NAN" (case insensitive)
- "0x" or "0X", an input field of hexadecimal digits and optionally a decimal point character, and optionally followed by a "p" or "P" a plus or minus sign and a decimal exponent
- An input field of decimal digits and optionally a decimal point character and optionally an "e" or "E" a plus or minus sign and a non-empty exponent
Note that if your locale
defines any other expression as an acceptable floating point input field this is also accepted. So if you've added some special sauce to the istream
you're working with that may be where the problem lies. Outside of that, neither a trailing "a", "b", or "x" are an accepted suffix for the %lg
conversion specifier, so your implementation is not compliant or there's something else you're not telling us.
Here is a live example of your inputs succeeding on gcc5.1 which is compliant: http://ideone.com/nGGW0L
Since the problem is caused by a bug (or feature, depending on your point of view), in libc++, it seems that the easiest way to avoid it is to use libstdc++ instead, until a fix is in place. If you're running on a mac, add -stdlib=libstdc++ to your compile flags. g++ -stdlib=libstdc++ test.cpp will correctly compile the code given in this post.
Libc++ appears to have other, similar, bugs, one of which I posted here: Trying to read lines from an ASCII file using C++ , Ubuntu vs Mac...?, before learning about these different libraries.
来源:https://stackoverflow.com/questions/37459179/c-reading-a-double-followed-by-a-character-from-cin