Read uint8_t from std::stringstream as a numeric type

前端 未结 3 671
自闭症患者
自闭症患者 2020-12-11 15:43

My understanding is that reading a uint8_t from a stringstream is a problem because the stringstream will interpret the uint8_t<

相关标签:
3条回答
  • 2020-12-11 16:02

    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

    0 讨论(0)
  • 2020-12-11 16:10

    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.

    0 讨论(0)
  • 2020-12-11 16:27

    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.

    0 讨论(0)
提交回复
热议问题