C++序列化对象时内存出现额外'0b'字节的问题排查
问题根源与解决方案
你遇到的额外字节问题,核心原因是混用了格式化输出操作符<<和二进制写入write,<<是用于文本格式化输出的工具,不适合直接处理二进制字节数据。
具体问题分析
os << H.CID的风险:CID是unsigned char数组,<<会把它当作C风格字符串处理,从数组起始位置一直输出到内存中第一个\0为止。你的CID是16个0x01,没有终止符,这会导致未定义行为——虽然当前序列化前16字节看似正确,但本质是依赖了内存中的随机内容,非常危险。os << unsigned char的转换问题:对于Version、FirstTwoCode、LastTwoCode这类单字节字段,<<会将其视为ASCII字符输出。在文本模式流中,部分控制字符(比如你遇到的0x0B,即垂直制表符)会被流自动转换为多字节序列,这就是额外0x0B字节出现的直接原因。- 格式化输出破坏二进制写入:前面的
<<操作已经改变了流的状态和内容,后续write写入的Payload_size数据位置被干扰,导致原始字节(如0xCC)丢失。
修复代码
把所有格式化输出替换为ostream::write,直接写入原始字节,同时修正类的访问权限问题:
#include <cstring> #include <ostream> // 先声明Header类,避免友元声明报错 class Header; std::ostream& operator << (std::ostream& os, const Header& H); class Header { private: UINT8 CID[CLIENTID_BYTE_SIZE]; unsigned char Version; unsigned char FirstTwoCode; unsigned char LastTwoCode; int Payload_size ; public: Header(UINT8 clientID[CLIENTID_BYTE_SIZE], int request_code, int PL_SIZE); // 声明友元,让operator<<能访问私有成员 friend std::ostream& operator << (std::ostream& os, const Header& H); }; Header::Header(UINT8 clientID[CLIENTID_BYTE_SIZE], int request_code, int PL_SIZE) { memcpy(CID, clientID, CLIENTID_BYTE_SIZE); Version = static_cast<unsigned char>(VERSION_NUMBER); FirstTwoCode = static_cast<unsigned char>(request_code / 100); LastTwoCode = static_cast<unsigned char>(request_code % 100); Payload_size = PL_SIZE; } std::ostream& operator << (std::ostream& os, const Header& H) { // 直接写入CID的所有字节 os.write(reinterpret_cast<const char*>(H.CID), CLIENTID_BYTE_SIZE); // 依次写入单字节字段 os.write(reinterpret_cast<const char*>(&H.Version), sizeof(H.Version)); os.write(reinterpret_cast<const char*>(&H.FirstTwoCode), sizeof(H.FirstTwoCode)); os.write(reinterpret_cast<const char*>(&H.LastTwoCode), sizeof(H.LastTwoCode)); // 写入Payload_size(注意字节序问题,下文补充) os.write(reinterpret_cast<const char*>(&H.Payload_size), sizeof(H.Payload_size)); return os; }
额外注意事项
- 二进制模式流:如果用
stringstream序列化,建议显式指定二进制模式,避免不同平台的文本模式转换差异:std::stringstream ss(std::ios::binary); ss << your_header; - 字节序兼容:
int类型的Payload_size直接写入内存会使用主机字节序(小端/大端),跨平台通信时需要统一为网络字节序(大端):// 序列化时转换为网络字节序 int payload_network = htonl(H.Payload_size); os.write(reinterpret_cast<const char*>(&payload_network), sizeof(payload_network)); // 接收端转换回主机字节序 int payload_host = ntohl(received_payload);
内容的提问来源于stack exchange,提问作者adam
相关产品推荐
相关产品推荐

