By bremen_matt


2019-02-11 09:13:59 8 Comments

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...
   }

3 comments

@Daniel Langr 2019-02-11 09:47:56

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.

@bremen_matt 2019-02-11 10:05:57

This looks nice. If you put it in an anonymous namespace, then I imagine that any damage would be limited

@bremen_matt 2019-02-11 10:10:36

And although I just asked about stringstreams, I guess you could easily change that stringstream to istream, and then are covered for all input streams.

@Daniel Langr 2019-02-11 10:18:46

@bremen_matt It doesn't seem to be so simple. Look here: wandbox.org/permlink/8a2kGAywWyJUfPzr. The compiler obviously gives precedence to the simple implicit conversion of ui to char before pairing str with ss by derived-to-base conversion. Not sure how to solve this.

@bremen_matt 2019-02-11 10:27:31

std::istream& operator>>(std::istream& str, uint8_t& num)... Forget the template and #include <istream>

@bremen_matt 2019-02-11 10:28:58

Btw, I had never heard of Wandbox. I love how you can switch the compiler like that...

@Daniel Langr 2019-02-11 10:29:28

@bremen_matt Yes, just then it will not cover all input streams. But you are likely fine with that.

@Daniel Langr 2019-02-11 10:30:52

@bremen_matt I like it so much for simple experiments. Especially because it supports Vim-like source editing, which I havne't seen in other online IDEs (like in popular IdeOne or Coliru).

@Arne Vogel 2019-02-11 12:39:43

num = std::min(temp, (uint16_t)max); – This has an implicit conversion, which is not so nice (and neither is the C-style cast). I will admit though that num = static_cast<uint8_t>(std::min(temp, static_cast<uint16_t>(max))); is not elegant either. Maybe move the assignment into the if rsp. a newly created else branch.

@Arne Vogel 2019-02-11 12:54:23

@DanielLangr "The compiler obviously gives precedence to the simple implicit conversion of ui to char." – This kind of implicit conversion does not apply to references. There is an unsigned char & overload for the std::operator>> for streams however. I'm not sure what causes the apparent ambiguity to be resolved in favor of the std version but highly suspect the following specialization in libstdc++: extern template istream& operator>>(istream&, unsigned char&); – It goes to show that it's a really bad idea to make ambiguous overloads of standard functions, I guess.

@Daniel Langr 2019-02-11 13:00:00

@ArneVogel Agree, I would better use only a version where no conversion is required in this case, such as the shown one for std::stringstream.

@Daniel Langr 2019-02-11 13:06:13

@ArneVogel Ooh, see your point now. I didn't mention the overloads for unsigned char before (eel.is/c++draft/input.streams#istream.extractors). This solution might be really fragile. I will put a note into the answer about it.

@Hanjoung Lee 2019-02-11 09:42:11

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

@bremen_matt 2019-02-11 09:48:05

I wouldn't really call this an "answer", but this is very very useful information.

@bremen_matt 2019-02-11 09:40:36

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.

Related Questions

Sponsored Content

9 Answered Questions

[SOLVED] Read whole ASCII file into C++ std::string

10 Answered Questions

0 Answered Questions

Am I Using Stringstream Wrong?

2 Answered Questions

meaning and debuging (print) of uint8_t* value in c++

7 Answered Questions

[SOLVED] Pretty-print C++ STL containers

2 Answered Questions

[SOLVED] Addition of two matrix using struct

1 Answered Questions

[SOLVED] Passing stringstream as ostream&, no content being read

0 Answered Questions

2 Answered Questions

[SOLVED] No match for "operator<<" in std::operator

  • 2015-06-23 20:33:03
  • Raghib Hasan
  • 142 View
  • 1 Score
  • 2 Answer
  • Tags:   c++

1 Answered Questions

[SOLVED] filestream reading hexadecimal file into binary buffer

  • 2014-09-26 12:27:53
  • Nuclear
  • 521 View
  • 0 Score
  • 1 Answer
  • Tags:   c++ iostream

Sponsored Content