Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read uint8_t from std::stringstream as a numeric type

Tags:

c++

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...
   }
like image 767
bremen_matt Avatar asked Feb 11 '19 09:02

bremen_matt


People also ask

What type is Stringstream?

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.

Is Stringstream deprecated?

strstream has been deprecated since C++98, std::stringstream and boost::iostreams::array are the recommended replacements.

What is the difference between string and Stringstream?

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.


3 Answers

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

like image 80
Hanjoung Lee Avatar answered Oct 23 '22 11:10

Hanjoung Lee


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.

like image 7
Daniel Langr Avatar answered Oct 23 '22 11:10

Daniel Langr


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.

like image 1
bremen_matt Avatar answered Oct 23 '22 11:10

bremen_matt