序列化对象的字节数组中的C ++ [英] Serializing object to byte-array in C++

查看:148
本文介绍了序列化对象的字节数组中的C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的工作是嵌入式设备(微控制器)上,并且我要救的对象到永久存储(EEPROM中)。大部分的系列化解决方案,我能找到的,使用的文件系统以某种方式,但我的目标没有文件系统。

所以我的问题是,我怎么可以将对象序列化到一个字节数组,所以我可以说字节数组保存到EEPROM后来呢?

下面是什么,我试图做一个例子:

 类Person {
     //构造函数,getter和setter方法​​省略    而无效(){
         字符缓冲区[sizeof的(人);
         序列化(缓冲液);
         EEPROM ::保存(缓冲区的sizeof(人));
    }    无效的load(){
         字符缓冲区[sizeof的(人);
         EEPROM ::负载(缓冲区的sizeof(人));
         反序列化(缓冲);
    }    无效连载(字符*结果){
        // ?????
    }    人反序列化(的char *缓冲区){
        // ??????
    }私人的:
    字符*名称;
    INT年龄;
    浮重;
};


解决方案

这可能是因为你的code为保存负荷将是相当通用的,将工作最好在一个单独的经理级,每留下数据类只与呈现本身作为重新装载的责任:

  //接口类
类序列化
{
上市:
    虚拟为size_t serialize_size()const的= 0;
    虚拟无效连载(字符* DATAOUT)常量= 0;
    虚拟无效反序列化(为const char * DATAIN)= 0;
};//加载/保存经理
类EEPromManager
{
上市:
    而无效(const的序列化和放大器; S)
    {
        字符*的数据;
        为size_t DATA_LEN;
        reserve_memory(数据,DATA_LEN,S);
        s.serialize(数据);
        EEPROM ::保存(数据,DATA_LEN);
        删除[]的数据;
    }    无效负载(序列化和放大器; S)
    {
        字符*的数据;
        为size_t DATA_LEN;
        reserve_memory(数据,DATA_LEN,S);
        EEPROM ::负载(数据,DATA_LEN);
        s.deserialize(数据);
        删除[]的数据;
    }私人的:
    字符* reserve_memory(字符*&放大器;数据,为size_t和放大器; DATA_LEN,常量序列化和放大器; S)
    {
        返回新的char [s.serialize_size()];
    }
};

每个你打算序列化/类反序列化应该从哪个强制要求使用这些功能的虚拟接口的接口继承。请注意,您需要在这里做自己的内存管理。我给了一个简单的例子,但你可能会想一些更稳健。

则每个函数都应该按顺序串行化类的所有属性(链基地班,并呼吁如果需要序列化上聚合对象。)

 类人:公共序列化
{
上市:
    虚拟为size_t serialize_size()const的
    {
        返回SerializablePOD<字符*> :: serialize_size(名)+
               SerializablePOD< INT> :: serialize_size(年龄)+
               SerializablePOD<浮动> :: serialize_size(重量);
    }    虚拟无效连载(字符* DATAOUT)常量
    {
        DATAOUT = SerializablePOD< char *之> ::连载(DATAOUT,名);
        DATAOUT = SerializablePOD< INT> ::连载(DATAOUT,年龄);
        DATAOUT = SerializablePOD<浮动> ::连载(DATAOUT,重量);
    }
    虚拟无效反序列化(为const char * DATAIN)
    {
        DATAIN = SerializablePOD< char *之> ::反序列化(DATAIN,名);
        DATAIN = SerializablePOD< INT> ::反序列化(DATAIN,年龄);
        DATAIN = SerializablePOD<浮动> ::反序列化(DATAIN,重量);
    }私人的:
    字符*名称;
    INT年龄;
    浮重;
};

您会从通用code受益序列化/反序列化每​​个单独的类型,这样你不保持有code写串等,即长度一个序列化/反序列化每​​个POD类型:

 模板< typename的POD>
类SerializablePOD
{
上市:
    静态为size_t serialize_size(POD STR)
    {
        返回的sizeof(POD);
    }
    静态的char *连载(字符*目标,POD值)
    {
        返回的memcpy(目标,&安培;价值,serialize_size(值));
    }
    静态为const char *反序列化(为const char *源,POD和放大器;目标)
    {
        的memcpy(安培;目标源,serialize_size(目标));
        返回源+ serialize_size(目标);
    }
};模板<>
为size_t SerializablePOD< char *之> :: serialize_size(字符*海峡)
{
    返回的sizeof(为size_t)+ strlen的(STR);
}模板<>
为const char * SerializablePOD< char *之> ::反序列化(为const char *源的char *&安培;目标)
{
    为size_t长度;
    的memcpy(安培;长度,源的sizeof(为size_t));
    的memcpy(安培;目标,源+的sizeof(为size_t),长度);
    返回源+的sizeof(为size_t)+长;
}

顺便说一下,您可能还需要考虑,如果你改变一个对象的架构在软件升级会发生什么。您保存的对象将可能被破坏的重装,除非你code这一轮使用 - 例如 - 一类版本标识符

最后的思考:在微观层面,你在做什么是类似于POD数据序列进行网络传输的方式方法很多,所以它可能是你可以利用库来做到这一点 - 即使你不必访问操作系统。

I am working on an embedded device (microcontroller), and I want to save objects to permanent storage (an EEPROM). Most of the serialization solutions I can find, use the file-system in some way, but my target has no file-system.

Therefore my question is, how can I serialize an object to a byte-array so I can save that byte-array to an EEPROM afterwards?

Here is an example of what i am trying to do:

class Person{
     //Constructor, getters and setters are omitted

    void save(){
         char buffer[sizeof(Person)]; 
         serialize(buffer);
         EEPROM::Save(buffer, sizeof(Person)); 
    }

    void load(){
         char buffer[sizeof(Person)]; 
         EEPROM::Load(buffer, sizeof(Person));
         deserialize(buffer);
    }

    void serialize(char* result){
        //?????
    }

    Person deserialize(char* buffer){
        //??????
    }

private:
    char* name;  
    int   age; 
    float weight; 
};

解决方案

It's likely that your code for save and load will be reasonably generic and would work best in a separate 'manager' class, leaving each data class only with the responsibility of rendering itself as re-loadable:

// Interface class
class Serializable
{
public:
    virtual size_t serialize_size() const = 0;
    virtual void serialize(char* dataOut) const = 0;
    virtual void deserialize(const char* dataIn) = 0;
};

// Load / save manager
class EEPromManager
{
public:
    void save( const Serializable& s )
    {
        char * data;
        size_t data_len;
        reserve_memory( data, data_len, s );
        s.serialize( data );
        EEPROM::Save( data , data_len );
        delete [] data;
    }

    void load( Serializable& s )
    {
        char * data;
        size_t data_len;
        reserve_memory( data, data_len, s );
        EEPROM::Load( data, data_len );
        s.deserialize( data );
        delete [] data;
    }

private:
    char* reserve_memory( char*& data, size_t& data_len, const Serializable& s )
    {
        return new char[ s.serialize_size() ];
    }
};

Each class you intend to serialize / de-serialize should inherit from an interface which mandates the virtual interface for these functions. Note that you'll need to do your own memory management here. I've given a simple example but you'd probably want something a bit more robust.

Then each function should sequentially serialize all attributes of the class (chaining bases classes and calling serialize on aggregate objects if needed.)

class Person : public Serializable
{
public:
    virtual size_t serialize_size() const
    {
        return SerializablePOD<char*>::serialize_size(name) +
               SerializablePOD<int>::serialize_size(age) +
               SerializablePOD<float>::serialize_size(weight);
    }

    virtual void serialize(char* dataOut) const
    {
        dataOut = SerializablePOD<char*>::serialize(dataOut, name);
        dataOut = SerializablePOD<int>::serialize(dataOut, age);
        dataOut = SerializablePOD<float>::serialize(dataOut, weight);
    }
    virtual void deserialize(const char* dataIn)
    {
        dataIn = SerializablePOD<char*>::deserialize(dataIn, name);
        dataIn = SerializablePOD<int>::deserialize(dataIn, age);
        dataIn = SerializablePOD<float>::deserialize(dataIn, weight);
    }

private:
    char* name;
    int   age;
    float weight;
};

You'll benefit from generic code to serialize / de-serialize each separate type so you don't keep having code to write the length of strings etc. I.e. a serialize / de-serialize for each POD type:

template <typename POD>
class SerializablePOD
{
public:
    static size_t serialize_size(POD str)
    {
        return sizeof(POD);
    }
    static char* serialize( char* target, POD value )
    {
        return memcpy( target, &value, serialize_size(value) );
    }
    static const char* deserialize( const char* source, POD& target )
    {
        memcpy( &target, source, serialize_size(target) );
        return source + serialize_size(target);
    }
};

template<>
size_t SerializablePOD<char*>::serialize_size(char* str)
{
    return sizeof(size_t) + strlen(str);
}

template<>
const char* SerializablePOD<char*>::deserialize( const char* source, char*& target )
{
    size_t length;
    memcpy( &length, source, sizeof(size_t) );
    memcpy( &target, source + sizeof(size_t), length );
    return source + sizeof(size_t) + length;
}

Incidentally, you might also need to consider what will happen if you change the schema of an object in a software upgrade. Your saved objects would potentially become corrupted on reloading, unless you code round this using - for example - a class version identifier.

Final thought: At a micro level, what you're doing is in many ways similar to the way POD data is serialised for network transmission, so it may be that you can take advantage of libraries to do that - even if you don't have access to an operating system.

这篇关于序列化对象的字节数组中的C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆