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; } }
修改点说明:
- 用
ss.write()写入原始字节,ss.read()读取原始字节,绕过文本格式化逻辑。 - 增加
ss.str("")清空流的内容,clear()仅重置流的状态标志位,不会清除已存储的数据。 - 读取前调用
ss.seekg(0)将读指针移到流的起始位置,确保从开头读取。 - 转换
c为unsigned int后再移位,避免符号扩展问题(虽然unsigned char本身无符号,但显式转换更安全)。
内容的提问来源于stack exchange,提问作者user180574
相关产品推荐
相关产品推荐

