You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++使用sstream序列化部分数值失败,求问题原因及解决方法

C++序列化代码部分数值处理失败的原因分析

问题描述

测试以下C++序列化代码时,部分数值处理失败:

#include <iostream>
#include <sstream>


int main()
{
   std::stringstream ss;

   for (unsigned int m = 0; m < 101; ++m)
   {
      ss.clear();

      unsigned int t = m;

      for (unsigned int i = 0; i < 4; ++i)
      {
         unsigned char c = t;
         ss << c;
         t >>= 8;
      }

      unsigned int n = 0;

      for (unsigned int i = 0, j = 0; i < 4; ++i, j += 8)
      {
         unsigned char c;
         ss >> c;
         n = n | (c << j);
      }

      if (n != m)
         std::cout << "not working for " << m << std::endl;
   }
}

运行结果:

not working for 9
not working for 10
not working for 11
not working for 12
not working for 13
not working for 32

核心原因

你错误地使用了文本格式化流操作符(<<和>>)来处理二进制序列化。这些操作符的设计目标是处理文本数据,而非原始字节:

  • 写入时:当unsigned char对应ASCII控制字符(比如9是制表符\t、10是换行\n、13是回车\r、32是空格),ss << c会将其作为文本控制字符处理,而非直接写入原始字节值。
  • 读取时:ss >> c会自动跳过所有空白字符(包括空格、制表符、换行、回车等),导致你无法正确读取之前写入的控制字符字节,最终拼接出的n与原始值m不符。

解决方案

改用流的二进制读写接口write()和read()来处理原始字节,避免文本格式化的干扰。修改后的代码如下:

#include <iostream>
#include <sstream>


int main()
{
   std::stringstream ss;

   for (unsigned int m = 0; m < 101; ++m)
   {
      ss.clear();
      ss.str(""); // 清空流内容,仅clear()只重置状态位,不清除已有数据

      unsigned int t = m;

      for (unsigned int i = 0; i < 4; ++i)
      {
         unsigned char c = t;
         ss.write(reinterpret_cast<const char*>(&c), sizeof(c));
         t >>= 8;
      }

      ss.seekg(0); // 将读指针重置到流开头

      unsigned int n = 0;

      for (unsigned int i = 0, j = 0; i < 4; ++i, j += 8)
      {
         unsigned char c;
         ss.read(reinterpret_cast<char*>(&c), sizeof(c));
         n = n | (static_cast<unsigned int>(c) << j);
      }

      if (n != m)
         std::cout << "not working for " << m << std::endl;
   }
}

修改点说明:

  1. 用ss.write()写入原始字节,ss.read()读取原始字节,绕过文本格式化逻辑。
  2. 增加ss.str("")清空流的内容,clear()仅重置流的状态标志位,不会清除已存储的数据。
  3. 读取前调用ss.seekg(0)将读指针移到流的起始位置,确保从开头读取。
  4. 转换c为unsigned int后再移位,避免符号扩展问题(虽然unsigned char本身无符号,但显式转换更安全)。

内容的提问来源于stack exchange,提问作者user180574

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 22:47:33