用C语言序列化数据结构

时间:2008-12-16 14:00:19

标签: c serialization

我想要一个可以将我的数据结构序列化到磁盘的C库,然后再加载它们。它应该接受任意嵌套的结构,可能还有循环引用。

我认为这个工具需要一个描述我的数据结构的配置文件。允许库使用代码生成,尽管我很确定没有它就可以这样做。

注意我对数据可移植性不感兴趣。我想将它用作缓存,所以我可以依赖不改变的环境。

感谢。


结果

有人建议Tpl这是一个很棒的库,但我相信它不会做任意对象图,例如每个包含两个其他节点的节点树。

另一位候选人是Eet,这是Enlightenment窗口管理器的一个项目。看起来很有趣但是,似乎没有能力序列化嵌套结构。

10 个答案:

答案 0 :(得分:16)

结帐tpl。从概述:

  

Tpl是一个用于序列化C的库   数据。数据存储在其中   自然二进制形式。 API很小   并试图保持“不在路上”。   与使用XML相比,tpl更快   并且更容易在C程序中使用。 TPL   可以序列化许多C数据类型,   包括结构。

答案 1 :(得分:10)

我知道你要的是一个图书馆。如果你找不到一个(:: boggle ::,你认为这是一个已经解决的问题!),这里有一个解决方案的大纲:

您应该能够编写代码生成器[1]来序列化树/图,而不需要(运行时)预处理。

您需要解析节点结构(typedef处理?),并以直接的方式编写包含的数据值,但要小心处理指针。

  • 对于单独引用您知道的其他对象(即char *name;)的指针,您可以直接序列化目标数据。

  • 对于可能被多次引用的对象以及树的其他节点,您必须表示指针结构。每个对象都被分配一个序列号,这是指针写入的内容。保持当前内存位置和序列号之间的转换结构。在遇到指针时,查看它是否已经分配了一个数字,如果没有,则给它一个并将该对象排队以进行序列化。

回读还需要一个节点 - #/内存位置转换步骤,并且在两次传递中可能更容易做到:用指针槽中的节点号重新生成节点(坏指针,被警告)以找出哪里每个节点都被放置,然后再次走结构修复指针。

我对tpl一无所知,但你可能会捎带它。


磁盘/网络格式应该包含某些类型信息。你需要一个名称修改方案。


[1] ROOT使用此机制在C ++中提供非常灵活的序列化支持。


迟到:我觉得这并不总是像上面暗示的那样容易。考虑以下(设计和设计不当)声明:

enum {
   mask_none = 0x00,
   mask_something = 0x01,
   mask_another = 0x02,
   /* ... */
   mask_all = 0xff
};
typedef struct mask_map {
   int mask_val;
   char *mask_name;
} mask_map_t;
mask_map_t mask_list[] = {
   {mask_something, "mask_something"},
   {mask_another, "mask_another"},
   /* ... */
};
struct saved_setup {
   char* name;
   /* various configuration data */
   char* mask_name;
   /* ... */
};

并假设我们初始化了struct saved_setup项,以便mask_name指向mask_list[foo].mask_name

当我们去序列化数据时,我们如何处理struct saved_setup.mask_name

您需要注意设计数据结构和/或为序列化过程带来一些特定于案例的智能。

答案 2 :(得分:6)

这是我的解决方案。它使用我自己的malloc,free和mmap,munmap系统调用的实现。按照给定的示例代码。参考:http://amscata.blogspot.com/2013/02/serialize-your-memory.html

在我的方法中,我创建一个char数组作为我自己的RAM空间。然后有分配内存和释放它们的功能。创建数据结构后,使用mmap,我将char数组写入文件。

每当您想将其加载回内存时,都会有一个函数使用munmap将数据结构再次放入char数组。由于它具有指针的虚拟地址,因此您可以重新使用数据结构。这意味着,您可以创建数据结构,保存,加载,再次编辑,然后再次保存。

答案 3 :(得分:4)

您可以查看eet。用于存储C数据类型(包括嵌套结构)的enlightenment项目库。虽然几乎所有启蒙项目的lib都处于pre-alpha状态,但eet已经被释放。但是,我不确定它是否可以处理循环引用。可能不是。

答案 4 :(得分:3)

答案 5 :(得分:3)

你应该结帐gwlib。串行器/解串器是广泛的。并且有广泛的测试可供查看。 http://gwlib.com/

答案 6 :(得分:2)

我假设您正在谈论存储图形结构,如果没有则忽略......

如果您存储图表,我个人认为最好的想法是实现一个将图形转换为邻接矩阵的函数。然后,您可以创建一个将邻接矩阵转换为图形数据结构的函数。

这有三个好处(在您的申请中可能或可能不重要):

  • 邻接矩阵是一种非常自然的方式来创建和存储图形
  • 您可以创建邻接矩阵并将其导入应用程序
  • 您可以以有意义的方式存储和读取数据。

我在CS项目中使用过这种方法,我肯定会再次这样做。

您可以在此处详细了解邻接矩阵:http://en.wikipedia.org/wiki/Modified_adjacency_matrix

答案 7 :(得分:1)

另一个选项是Avro C,是C中Apache Avro的实现。

答案 8 :(得分:1)

以下是使用Binn库(我的创建)的示例:

  binn *obj;

  // create a new object
  obj = binn_object();

  // add values to it
  binn_object_set_int32(obj, "id", 123);
  binn_object_set_str(obj, "name", "Samsung Galaxy Charger");
  binn_object_set_double(obj, "price", 12.50);
  binn_object_set_blob(obj, "picture", picptr, piclen);

  // send over the network
  send(sock, binn_ptr(obj), binn_size(obj));

  // release the buffer
  binn_free(obj);

如果您不想使用字符串作为键,可以使用使用整数作为键的binn_map。

还支持列表,所有这些结构都可以嵌套:

  binn *list;

  // create a new list
  list = binn_list();

  // add values to it
  binn_list_add_int32(list, 123);
  binn_list_add_double(list, 2.50);

  // add the list to the object
  binn_object_set_list(obj, "items", list);

  // or add the object to the list
  binn_list_add_object(list, obj);

答案 9 :(得分:0)

理论上,YAML应该做你想做的事http://code.google.com/p/yaml-cpp/

如果它适合您,请告诉我。