The title is pretty self explanatory.
char c = std::cin.peek(); // sets c equal to character in stream
I just realized that perhaps native type char can't hold the EOF.
thanks, nmr
The title is pretty self explanatory.
char c = std::cin.peek(); // sets c equal to character in stream
I just realized that perhaps native type char can't hold the EOF.
thanks, nmr
Short answer: No. Use int instead of char.
Slightly longer answer: No. If you can get either a character or the value EOF from a function, such as C's getchar and C++'s peek, clearly a normal char variable won't be enough to hold both all valid characters and the value EOF.
Even longer answer: It depends, but it will never work as you might hope.
C and C++ has three character types (except for the "wide" types): char, signed char and unsigned char. Plain char can be signed or unsigned, and this varies between compilers.
The value EOF is a negative integer, usually -1, so clearly you can't store it in an unsigned char or in a plain char that is unsigned. Assuming that your system uses 8-bit characters (which nearly all do), EOF will be converted to (decimal) 255, and your program will not work.
But if your char type is signed, or if you use the signed char type, then yes, you can store -1 in it, so yes, it can hold EOF. But what happens then when you read a character with code 255 from the file? It will be interpreted as -1, that is, EOF (assuming that your implementation uses -1). So your code will stop reading not just at the end of the file, but also as soon as it finds a 255 character.
Note that the return value of std::cin.peek()
is actually of type std::basic_ios<char>::int_type
, which is the same as std::char_traits<char>::int_type
, which is an int
and not a char
.
More important than that, the value returned in that int
is not necessarily a simple cast from char
to int
but is the result of calling std::char_traits<char>::to_int_type
on the next character in the stream or std::char_traits<char>::eof()
(which is defined to be EOF
) if there is no character.
Typically, this is all implemented in exactly the same way as fgetc
casts the character to an unsigned char
and then to an int
for its return value so that you can distinguish all valid character values from EOF
.
If you store the return value of std::cin.peek()
in a char
then there is the possiblity that reading a character with a positive value (say ÿ in a iso-8859-1 encoded file) will compare equal to EOF
.
The pedantic thing to do would be.
typedef std::istream::traits_type traits_type;
traits_type::int_type ch;
traits_type::char_type c;
while (!traits_type::eq_int_type((ch = std::cin.peek()), traits_type::eof()))
{
c = traits_type::to_char_type(ch);
// ...
}
This would probably be more usual:
int ch;
char c;
while ((ch = std::cin.peek()) != EOF)
{
c = std::iostream::traits_type::to_char_type(ch);
// ...
}
Note that it is important to convert the character value correctly. If you perform a comparison like this: if (ch == '\xff') ...
where ch
is an int
as above, you may not get the correct results. You need to use std::char_traits<char>::to_char_type
on ch
or std::char_traits<char>::to_int_type
on the character constant to get a consistent result. (You are usually safe with members of the basic character set, though.)