【问题标题】:pack any data type into vector <uint8_t>将任何数据类型打包到向量 <uint8_t>
【发布时间】:2014-11-04 20:43:22
【问题描述】:

这个问题很像

serialize any data type as vector<uint8_t> - use reinterpret_cast?

template <typename T>
inline void pack (std::vector< uint8_t >& dst, T& data) {
    uint8_t * src = static_cast < uint8_t* >(static_cast < void * >(&data));
    dst.insert (dst.end (), src, src + sizeof (T));
}

解压

template <typename T>
inline void unpack (vector <uint8_t >& src, int index, T& data) {
    copy (&src[index], &src[index + sizeof (T)], &data);
}

我正在尝试将任何类型的数据打包到一个字节数组中。

q1 :我有使用 uint8_t* 的繁琐实现,我希望向量的选择是最好的。

q2:我无法使用上述函数正确打包 std::string。请让我知道上述函数在打包所有类型的数据类型方面有多舒服

请告诉我如何将 std::string 合并到上述解决方案中,即打包并将 std::string 合并到向量中

我要打包的数据类型:

所有 POD 标准::字符串 矢量本身..

外部问题:

我想把这样的类打包成一个字节数组

class StartPeerSessionRequest : public Request {

public:
    StartPeerSessionRequest();
    virtual ~StartPeerSessionRequest();
    void composeRequestwithHardCodeValues();
    vector<uint8_t> packRequestWithTemplate();

private:
    uint16_t    mProtocolVersion;
    uint16_t    mSessionFlags;
    uint16_t    mMaxResponseLength;
    string      mMake;
    string      mModel;
    string      mSerialNumber;
    uint8_t     mTrackDelay;
    string      mHeadUnitModel;
    string      mCarModelYear;
    string      mVin;
    uint16_t    mVehicleMileage;
    uint8_t     mShoutFormat;
    uint8_t     mNotificationInterval;

};

class Message {

public:
    Message();
    virtual ~Message();
    void composeMessage(vector<uint8_t> data, uint16_t opcode, uint16_t lengthOfData);

    uint16_t packetheader;
    uint16_t length;
    uint16_t request_response_id;
    uint16_t opcode;
    uint16_t checksum;
    vector<uint8_t> data;
}

我选择的字节数组数据类型是vector(uint8_t)

我想将它写入设备文件或通过蓝牙网络发送。我不想反序列化同一个类。我将收到一个再次是字节数组的响应,我最终需要将响应解包到另一个类

【问题讨论】:

  • 如果你真的需要实现可移植的(通过有线(-less),针对不同的机器)序列化,那么看看像protocol-buffersboost-serialization这样的框架。
  • 上述函数只对POD类型有用。如果你想编写代码来序列化/反序列化 std::string,你必须实际去做。这并不难,但正确的做法很大程度上取决于你的外部问题——你打算用这些向量做什么?
  • 更新问题与外部问题

标签: c++ vector stdstring


【解决方案1】:

tl;dr: 使用像Boost.SerializationProtocol Buffers 这样的序列化库。

广告 1) 向量没问题。 编辑:但流会更好。

广告 2) 好吧,你不能用这种方式间接序列化对象,因为你只会得到指向实际数据的指针,而不是数据本身。而且只能序列化plain old data(standard layout in C++11)对象;或者更确切地说,不保证反序列化不是普通旧数据/标准布局的对象将导致工作对象。 std::string(也不是任何其他容器)不是 POD 并且包含间接(std::string 只是一种特殊的向量)。

在没有特殊支持的情况下,无法将任意非标准布局对象序列化/打包为字节数组。要么您必须为每种此类类型编写序列化和反序列化函数,要么您必须放弃字节数组要求并使用boost::any 之类的东西来维护类型信息并在幕后为您正确调用构造函数和析构函数。请注意,boost::any 本身是一个非标准布局对象,具有间接性。

广告编辑:

我不想反序列化同一个类。

是的,你知道。在连接的另一端。所以要么

  1. 另一端使用相同的结构,你必须同时编写序列化和反序列化,一个在一端使用,另一个在另一端,
  2. 另一端使用不同的结构(甚至可能使用不同的语言)并且您在双方都工作,因此您必须编写匹配的序列化和反序列化,或者
  3. 另一端由其他人编写,您必须编写序列化以使用特定的约定格式。

有数千种方法可以序列化每种类型。一个字符串可以被序列化为长度和内容或以指定终止符(通常为0字节)结束的内容,一个整数(并且字符串大小是一个整数)可以被序列化为不同的固定字节数,以不同的顺序(endian),使用变量长度编码等

然后有变化。我看到您确实包含了协议版本。但是您还必须编写反序列化代码以根据版本执行不同的操作,这通常意味着无论如何都要逐个成员执行(您希望输出独立于版本的相同结构以保持下游代码健全)等。

如果您没有决定协议,我建议您查看Boost.SerializationProtocol Buffers 库。

  • Boost.Serialization 很好地粘合到现有对象中,但特定于 C++ 并且仅提供向后兼容性,即如果发送方发送版本 2 而接收方未更新,则根本无法理解该消息。
  • Protocol Buffers 需要以它的特殊格式定义消息并从中生成 C++ 定义,但是大多数语言都有生成器并且它支持前向兼容性,即如果发送方发送版本 2,接收方将理解所有已经存在的字段在版本 1 中并忽略那些不是的。

如果由于某种原因您不能使用它们(除非目标受到极大限制,否则您应该能够使用;我在使用 Boost 和 Protobuf 并在所有当前主要移动平台上运行的移动应用程序上工作),至少阅读他们的技术描述,并可能查看代码,以便您知道如何做好序列化。

【讨论】:

  • 感谢您的帮助,请解决序列化/反序列化问题。我只想打包成一个字节数组。并且还将另一个字节数组解压缩为几种数据类型。请让我知道任何通用的可读解决方案谢谢
  • @MarshelAbraham:想想我用的是“pack”/“unpack”而不是“serialize”/“deserialize”;它们是此目的的同义词。
  • 请告诉我任何解决方案只是将字符串打包到向量,将 cstring 版本传递给上述模板函数会有所帮助吗?或者让我知道任何其他解决方案谢谢
  • @MarshelAbraham:我已经添加了关于您的编辑的长部分。
  • @MarshelAbraham:顺便说一句,您为什么要解决序列化/反序列化问题?你做的是最一般的serialize/deserialize,不同平台之间的网络传输(从成员名来看,发送者几乎肯定是嵌入式系统)。
猜你喜欢
  • 1970-01-01
  • 2011-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-21
  • 2012-11-06
  • 1970-01-01
相关资源
最近更新 更多