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

C++序列化对象时内存出现额外'0b'字节的问题排查

问题根源与解决方案

你遇到的额外字节问题,核心原因是混用了格式化输出操作符<<和二进制写入write,<<是用于文本格式化输出的工具,不适合直接处理二进制字节数据。

具体问题分析

  1. os << H.CID的风险:CID是unsigned char数组,<<会把它当作C风格字符串处理,从数组起始位置一直输出到内存中第一个\0为止。你的CID是16个0x01,没有终止符,这会导致未定义行为——虽然当前序列化前16字节看似正确,但本质是依赖了内存中的随机内容,非常危险。
  2. os << unsigned char的转换问题:对于Version、FirstTwoCode、LastTwoCode这类单字节字段,<<会将其视为ASCII字符输出。在文本模式流中,部分控制字符(比如你遇到的0x0B,即垂直制表符)会被流自动转换为多字节序列,这就是额外0x0B字节出现的直接原因。
  3. 格式化输出破坏二进制写入:前面的<<操作已经改变了流的状态和内容,后续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;
}

额外注意事项

  1. 二进制模式流:如果用stringstream序列化,建议显式指定二进制模式,避免不同平台的文本模式转换差异:
    std::stringstream ss(std::ios::binary);
    ss << your_header;
    
  2. 字节序兼容: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 17:15:53