如何将Data类成员的所有字节数组打包到单个vector并实现序列化反序列化
Data类序列化与反序列化问题解答
Q1:合并后的字节vector如何拆分?是否需要分隔符?
不需要额外加分隔符——因为你要序列化的每个数据类型的字节长度是固定的:
- int32固定占4字节
- int64固定占8字节(你代码里的示例输出是6字节,应该是笔误)
- float固定占4字节
- double固定占8字节
合并字节序列的方法
把各个成员的字节数据依次追加到总vector即可:
- 调用
encode得到int32的字节序列,用vector::insert插入到总vector末尾 - 同理插入int64的字节序列
- 将float的二进制字节(通过memcpy得到的数组)逐个转成
uint8_t,插入总vector - 最后处理double的二进制字节,同样插入总vector
反序列化拆分的方法
按照序列化时的固定顺序,依次截取对应长度的字节段解析:
- 从vector起始位置取前4字节,解析为int32
- 接着取接下来的8字节,解析为int64
- 再取4字节解析float
- 最后取8字节解析double
Q2:更优的实现方式
核心优化方向
- 跨平台字节序统一:不同机器的大端/小端字节序会导致解析失败,所以
encode/decode必须统一字节序(比如用网络字节序——大端),整数用htonl/ntohl、htonll/ntohll转换,浮点型也需要转成固定字节序后再序列化。 - 代码复用:用模板函数封装通用的序列化/反序列化逻辑,避免重复编写相似代码。
- 安全内存操作:用
std::copy或vector::insert配合指针范围代替手动memcpy,减少出错概率。 - 减少拷贝开销:反序列化时直接用指针偏移读取字节,不需要额外拷贝子vector。
优化后的示例代码
#include <vector> #include <cstring> #include <algorithm> #include <cstdint> #include <type_traits> // 假设Data类定义如下 struct Data { int32_t Int32; int64_t Int64; float Float; double Double; }; // 将int32转为大端字节序的vector std::vector<uint8_t> encode(int32_t value) { std::vector<uint8_t> bytes(4); const uint32_t be_val = htonl(static_cast<uint32_t>(value)); std::memcpy(bytes.data(), &be_val, sizeof(be_val)); return bytes; } // 将int64转为大端字节序的vector std::vector<uint8_t> encode(int64_t value) { std::vector<uint8_t> bytes(8); const uint64_t be_val = htonll(static_cast<uint64_t>(value)); std::memcpy(bytes.data(), &be_val, sizeof(be_val)); return bytes; } // 通用序列化单个值到目标vector template<typename T> void serialize_val(const T& val, std::vector<uint8_t>& out) { if constexpr (std::is_same_v<T, float>) { uint32_t tmp; std::memcpy(&tmp, &val, sizeof(float)); tmp = htonl(tmp); const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&tmp); out.insert(out.end(), bytes, bytes + sizeof(float)); } else if constexpr (std::is_same_v<T, double>) { uint64_t tmp; std::memcpy(&tmp, &val, sizeof(double)); tmp = htonll(tmp); const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&tmp); out.insert(out.end(), bytes, bytes + sizeof(double)); } else { auto bytes = encode(val); out.insert(out.end(), bytes.begin(), bytes.end()); } } std::vector<uint8_t> serialize(Data& D) { std::vector<uint8_t> serialized_data; serialize_val(D.Int32, serialized_data); serialize_val(D.Int64, serialized_data); serialize_val(D.Float, serialized_data); serialize_val(D.Double, serialized_data); return serialized_data; } // 从字节指针解析int32(大端转主机序) int32_t decode_int32(const uint8_t* bytes) { uint32_t be_val; std::memcpy(&be_val, bytes, sizeof(be_val)); return static_cast<int32_t>(ntohl(be_val)); } // 从字节指针解析int64(大端转主机序) int64_t decode_int64(const uint8_t* bytes) { uint64_t be_val; std::memcpy(&be_val, bytes, sizeof(be_val)); return static_cast<int64_t>(ntohll(be_val)); } // 通用从字节指针反序列化单个值 template<typename T> T deserialize_val(const uint8_t*& ptr) { T result; if constexpr (std::is_same_v<T, float>) { uint32_t tmp; std::memcpy(&tmp, ptr, sizeof(float)); tmp = ntohl(tmp); std::memcpy(&result, &tmp, sizeof(float)); ptr += sizeof(float); } else if constexpr (std::is_same_v<T, double>) { uint64_t tmp; std::memcpy(&tmp, ptr, sizeof(double)); tmp = ntohll(tmp); std::memcpy(&result, &tmp, sizeof(double)); ptr += sizeof(double); } else if constexpr (std::is_same_v<T, int32_t>) { result = decode_int32(ptr); ptr += sizeof(int32_t); } else if constexpr (std::is_same_v<T, int64_t>) { result = decode_int64(ptr); ptr += sizeof(int64_t); } return result; } Data deserialize(std::vector<uint8_t>& Bytes) { Data D2; const uint8_t* ptr = Bytes.data(); D2.Int32 = deserialize_val<int32_t>(ptr); D2.Int64 = deserialize_val<int64_t>(ptr); D2.Float = deserialize_val<float>(ptr); D2.Double = deserialize_val<double>(ptr); return D2; }
内容的提问来源于stack exchange,提问作者Sao Petrik
相关产品推荐
相关产品推荐

