C语言实现一个简单的序列化和反序列化框架

C语言实现一个简单的序列化和反序列化框架

github:https://github.com/lhz3238734725/C_Serialize-Framework

序列化和反序列化的概念

序列化:把对象转换为字节序列的过程称为对象的序列化.
反序列化:把字节序列恢复为对象的过程称为对象的反序列化.
在C语言中,“对象”指的就是我们的结构体,将结构体数据转换成流数据(uint8_t)的过程为序列化;将流数据(uint8_t)还原成结构体数据的过程我们称之为反序列化。

实现原理

首先我们简单定义一个结构体:

struct test {
    uint8_t val_1;
    int val_2;
    long val_3;
};

那么如何实现上述结构体的序列化呢?

C语言的结构体数据会自动内存对齐,缺少的部分用0填充,而这部分数据是我们不需要的。
我们简单思考一下,其实很简单:

  1. 定义一个 uint8_t *buf;
  2. 将test结构体的数据依次拷贝进入 buf

是不是很简单,对,就是这么简单。我们只需要知道每个成员的大小,以及在结构体中的偏移量,我们就可以根据这两个属性实现一个结构体的序列化。当然,指针数据 应该怎么办呢?这个我们下面在讨论。

*那么如何将 uint8_t buf 数据反序列化为结构体呢?

其实也不难,除了 成员大小,偏移量 ,我们还需要知道成员名称,例如上述的 val_l, val_2 等
知道了这些信息,我们可以先创建一个结构体,然后根据这三个信息,将相应位置的数据复制给 相应的属性就行

整体实现思路

第一步:我们对结构体数据进行分类:

  1. 普通数据(C语言标准类型数据 int char long ...)
  2. 普通数据数组(int *, char *, long *....)
  3. 对象数据(自定义的结构体 struct test *)
  4. 对象数据数组(struct test **)

为了方便,数组数据不采用 int[n] 这种类型,全部采用 长度 + 指针的形式表示

// 定义标准数据类型 标准数据类型数组
#define SF_PACK_DEF_VAR(type, var)      type var
#define SF_PACK_DEF_VARS(type, vars)    uint64_t n_##vars; type* vars

// 定义自定义结构体类型 自定义结构体类型数组
#define SF_PACK_DEF_OBJ(type, obj)      type* obj
#define SF_PACK_DEF_OBJS(type, objs)    uint64_t n_##objs; type** objs

第二步:定义一个成员信息结构体,用于记录成员的信息(名称,大小,偏移量等)

struct sf_pack_info_s
{
    const char *name;           // 名称
    uint64_t size;              // 偏移量
    uint64_t offset;            // 大小
    int64_t noffset;            // 用于数组,数组长度的偏移量
    int64_t msize;              // 数组成员的大小
    uint64_t n_members;         // 用于自定义结构体,自定义结构体成员信息数组长度
    sf_pack_info_t *members;    // 用于自定义结构体,自定义结构体成员信息数组
};

第三步:定义序列化反序列化接口

int sf_pack(void *p IN, sf_pack_info_t *infos IN, uint64_t n_infos IN, uint8_t **pbuf OUT, int *plen OUT);
int sf_unpack(void **pp OUT, sf_pack_info_t *infos IN, uint64_t n_infos IN, const uint8_t *buf IN, int len IN);
int sf_unpack_free(void *p IN, sf_pack_info_t *infos IN, uint64_t n_infos IN); 

第四步:定义成员信息数组宏

// 定义结构体成员信息数组
#define SF_PACK_INFO_TYPE(type) \
static sf_pack_info_t sf_pack_info_##type[] = { 

// 定义标准数据类型成员信息
#define SF_PACK_INFO_DEF_VAR(type, var) \
{ #var,  SF_SIZEOF(type, var), offsetof(type, var), -1, -1, 0, NULL } 

// 定义标准数据类型数组成员信息
#define SF_PACK_INFO_DEF_VARS(type, vars, vtype) \
{ "n_"#vars, SF_SIZEOF(type, n_##vars), offsetof(type, n_##vars), -1, -1, 0, NULL }, \
{ #vars, SF_SIZEOF(type, vars), offsetof(type, vars), offsetof(type, n_##vars), sizeof(vtype), 0, NULL }

// 定义自定义结构体成员信息
#define SF_PACK_INFO_DEF_OBJ(type, obj, objtype) \
{ #obj, SF_SIZEOF(type, obj), offsetof(type, obj), -1, -1, SF_PACK_N_INFOS(objtype), sf_pack_info_##objtype }

// 定义自定义结构体数组成员信息
#define SF_PACK_INFO_DEF_OBJS(type, objs, objtype) \
{ "n_"#objs, SF_SIZEOF(type, n_##objs), offsetof(type, n_##objs), -1, -1, 0, NULL }, \
{ #objs, SF_SIZEOF(type, objs), offsetof(type, objs), offsetof(type, n_##objs), sizeof(objtype*), SF_PACK_N_INFOS(objtype), sf_pack_info_##objtype }

// 结束定义
#define SF_PACK_INFO_END(type) \
}; \
static int sf_##type##_pack(type *p, uint8_t **pbuf, int *plen) \
{ \
    sf_pack(p, sf_pack_info_##type, SF_PACK_N_INFOS(type), pbuf, plen); \
} \
static int sf_##type##_unpack(type **pp, uint8_t *buf, int len) \
{ \
    sf_unpack((void**)pp, sf_pack_info_##type, SF_PACK_N_INFOS(type), buf, len); \
} \
static void sf_##type##_unpack_free(type *p) \
{ \
    sf_unpack_free(p, sf_pack_info_##type, SF_PACK_N_INFOS(type)); \
}

第五步:实现第三步的函数

参考

https://www.bilibili.com/video/BV1aF4m1L7bK?vd_source=30803ba1f5b5b8fcdce05ab90748f6b5

posted @ 2024-03-13 16:34  异世界穿越中!.!  阅读(1034)  评论(0)    收藏  举报