My understanding is that reading a uint8_t
from a stringstream
is a problem because the stringstream
will interpret the uint8_t
as a char
. I would like to know how I can read a uint8_t
from a stringstream
as a numeric type. For instance, the following code:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
uint8_t ui;
std::stringstream ss("46");
ss >> ui;
cout << unsigned(ui);
return 0;
}
prints out 52
. I would like it to print out 46
.
EDIT: An alternative would to just read a string
from the stringstream
and then convert the solution to uint8_t
, but this breaks the nice chaining properties. For example, in the actual code I have to write, I often need something like this:
void foobar(std::istream & istream){
uint8_t a,b,c;
istream >> a >> b >> c;
// TODO...
}
A stringstream class in C++ is a Stream Class to Operate on strings. The stringstream class Implements the Input/Output Operations on Memory Bases streams i.e. string: The stringstream class in C++ allows a string object to be treated as a stream. It is used to operate on strings.
strstream has been deprecated since C++98, std::stringstream and boost::iostreams::array are the recommended replacements.
Very Informally: A string is a collection of characters, a stream is a tool to manipulate moving data around. A string stream is a c++ class that lets you use a string as the source and destination of data for a stream.
Please do not use char
or unsigned char
(uint8_t) if you want to read in a formatted way. Your example code and its result is an expected behavior.
As we can see from https://en.cppreference.com/w/cpp/io/basic_istream/operator_gtgt2
template< class Traits >
basic_istream<char,Traits>& operator>>( basic_istream<char,Traits>& st, unsigned char& ch );
This does "Performs character input operations".
52
is an ascii code for '4'. Which means that the stringstream
has read only one byte and still ready to read '6'.
So if you want work in the desired way, you should use 2-byte or bigger integer types for sstream::operator>>
then cast it to uint8_t
- the exact way that you self-answered.
Here's a reference for those overloads. https://en.cppreference.com/w/cpp/io/basic_istream/operator_gtgt
You can overload the input operator>>
for uint8_t
, such as:
std::stringstream& operator>>(std::stringstream& str, uint8_t& num) {
uint16_t temp;
str >> temp;
/* constexpr */ auto max = std::numeric_limits<uint8_t>::max();
num = std::min(temp, (uint16_t)max);
if (temp > max) str.setstate(std::ios::failbit);
return str;
}
Live demo: https://wandbox.org/permlink/cVjLXJk11Gigf5QE
To say the truth I am not sure whether such a solution is problem-free. Someone more experienced might clarify.
UPDATE
Note that this solution is not generally applicable to std::basic_istream
(as well as it's instance std::istream
), since there is an overloaded operator>>
for unsigned char
: [istream.extractors]. The behavior will then depend on how uint8_t
is implemented.
After much back and forth, the answer seems to be that there is no standard way of doing this. The options are to either read off the uint8_t
as either a uint16_t
or std::string
, and then convert those values to uint8_t
:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
uint8_t ui;
uint16_t tmp;
std::stringstream ss("46");
ss >> tmp;
ui = static_cast<uint8_t>(tmp);
cout << unsigned(ui);
return 0;
}
However, such a solution disregards range checking. So you will need to implement that yourself if you need it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With