从 std::stringstream 读取uint8_t为数字类型

Read uint8_t from std::stringstream as a numeric type

本文关键字:数字 类型 uint8 std stringstream 读取      更新时间:2023-10-16

我的理解是,从stringstream读取uint8_t是一个问题,因为stringstream会将uint8_t解释为char。我想知道如何以数字类型从stringstream读取uint8_t。例如,以下代码:

#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    uint8_t ui;
    std::stringstream ss("46");
    ss >> ui;
    cout << unsigned(ui);
    return 0;
}

打印出52.我希望它打印出46.

编辑:另一种方法是从stringstream中读取string,然后将解决方案转换为uint8_t,但这破坏了良好的链接属性。例如,在我必须编写的实际代码中,我经常需要这样的东西:

   void foobar(std::istream & istream){
       uint8_t a,b,c;
       istream >> a >> b >> c;
       // TODO...
   }

您可以重载uint8_t的输入operator>>,例如:

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

现场演示:https://wandbox.org/permlink/cVjLXJk11Gigf5QE

说实话,我不确定这样的解决方案是否没有问题。更有经验的人可能会澄清。


更新

请注意,此解决方案通常不适用于std::basic_istream(以及它的实例std::istream(,因为unsigned char有一个重载operator>>:[istream.extractors]。然后,该行为将取决于uint8_t的实现方式。

如果您想以

格式化的方式阅读,请不要使用charunsigned char(uint8_t(。示例代码及其结果是预期行为。

正如我们从 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 );

这将执行"执行字符输入操作"。

52是"4"的ASCII代码。这意味着stringstream只读取了一个字节,并且仍然准备读取"6"。

因此,如果你想以所需的方式工作,你应该使用 2 字节或更大的整数类型进行sstream::operator>>然后将其转换为 uint8_t - 你自我回答的确切方式。

下面是这些重载的参考。https://en.cppreference.com/w/cpp/io/basic_istream/operator_gtgt

经过反复讨论,答案似乎是没有标准的方法可以做到这一点。选项是将uint8_t读出为uint16_tstd::string,然后将这些值转换为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;
}

但是,这样的解决方案忽略了范围检查。因此,如果需要,您将需要自己实现它。