45 votes

Sérialiser les structures de données en C

Je voudrais une bibliothèque C qui puisse sérialiser mes structures de données sur le disque, et les recharger plus tard. Elle devrait accepter des structures arbitrairement imbriquées, éventuellement avec des références circulaires.

Je présume que cet outil aurait besoin d'un fichier de configuration décrivant mes structures de données. La bibliothèque est autorisée à utiliser la génération de code, même si je suis presque sûr qu'il est possible de le faire sans.

Notez que je ne suis pas intéressé par la portabilité des données. J'aimerais l'utiliser comme un cache, afin de pouvoir compter sur le fait que l'environnement ne change pas.

Merci.


Résultats

Quelqu'un a suggéré Tpl qui est une bibliothèque géniale, mais je crois qu'elle ne fait pas les graphes d'objets arbitraires, comme un arbre de nœuds qui contiennent chacun deux autres nœuds.

Un autre candidat est Eet qui est un projet du gestionnaire de fenêtres Enlightenment. Il semble intéressant mais, encore une fois, il ne semble pas avoir la capacité de sérialiser les structures imbriquées.

17voto

Robert Gamble Points 41984

Vérifiez tpl . Depuis la vue d'ensemble :

Tpl est une bibliothèque permettant de sérialiser les données C de données. Les données sont stockées dans leur forme binaire naturelle. L'API est petite et essaie de rester "à l'écart". Par rapport à l'utilisation de XML, tpl est plus rapide et plus facile à utiliser dans les programmes C. et plus facile à utiliser dans les programmes C. Tpl peut sérialiser de nombreux types de données C, y compris les structures.

4 votes

Tpl ne semble pas supporter les structures imbriquées. Par exemple, un nœud qui peut contenir deux sous-nœuds.

2 votes

Un autre problème avec tpl est la portabilité limitée des flottants.

10voto

dmckee Points 50318

Je sais que vous demandez une bibliothèque. Si vous n'en trouvez pas (::boggle: :, on croirait que le problème est résolu !), voici l'ébauche d'une solution :

Vous devriez pouvoir écrire un générateur de code [1] pour sérialiser les arbres/graphes sans prétraitement (d'exécution) assez simplement.

Vous devrez analyser la structure des nœuds ( typedef ), et écrivez les valeurs de données incluses de manière directe, mais traitez les pointeurs avec précaution.

  • Pour les pointeurs vers d'autres objets (ex. char *name; ) que vous connaître sont référencés de manière unique, vous pouvez sérialiser les données cibles directement.

  • Pour les objets qui peuvent être référencés plusieurs fois et pour les autres nœuds de votre arbre, vous devrez représenter la structure des pointeurs. Chaque objet se voit attribuer un numéro de sérialisation, qui est ce qui est écrit à la place du pointeur. Maintenez une structure de traduction entre la position actuelle de la mémoire et le numéro de sérialisation. Lorsque vous rencontrez un pointeur, vérifiez si un numéro lui a déjà été attribué, sinon, attribuez-lui un numéro et mettez cet objet en file d'attente pour la sérialisation.

La relecture nécessite également une étape de traduction nœud-#/emplacement en mémoire, et pourrait être plus facile à faire en deux passes : régénérer les nœuds avec les numéros de nœuds dans les slots de pointeurs (mauvais pointeur, attention) pour trouver où chaque nœud est placé, puis parcourir à nouveau la structure en fixant les pointeurs.

Je n'y connais rien en tpl, mais vous pouvez peut-être vous en servir.


Le format sur disque/réseau devrait probablement être encadré par des informations de type. Vous aurez besoin d'un système de mélange de noms.


[1] Racine utilise ce mécanisme pour fournir un support de sérialisation très flexible en C++.


Ajout tardif : Il me semble que ce n'est pas toujours aussi facile que je l'ai laissé entendre ci-dessus. Considérons la déclaration suivante (inventée et mal conçue) :

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;
   /* ... */
};

et supposons que nous initalisons struct saved_setup afin que mask_name points à mask_list[foo].mask_name .

Quand nous allons sérialiser les données, que faisons-nous avec struct saved_setup.mask_name ?

Vous devrez faire attention à la conception de vos structures de données et/ou apporter une intelligence spécifique au processus de sérialisation.

0 votes

Merci pour cet excellent article. J'avais essentiellement ce plan en tête comme la "preuve d'existence" de la bibliothèque. La théorie est que toutes les bibliothèques que l'on peut imaginer en C ont été écrites. Je n'arrive pas à croire qu'il s'avère qu'elle n'existe pas. Je vais peut-être essayer d'écrire ce truc pendant les fêtes de Noël.

6voto

Amith Chinthaka Points 108

Voici ma solution. Elle utilise ma propre implémentation des appels système malloc, free et mmap, munmap. Suivez les codes d'exemple donnés. Ref : http://amscata.blogspot.com/2013/02/serialize-your-memory.html

Dans mon approche, je crée un tableau de chars comme mon propre espace RAM. Ensuite, il y a des fonctions pour allouer la mémoire et la libérer. Après avoir créé la structure de données, en utilisant mmap J'écris le tableau de chars dans un fichier.

Chaque fois que vous voulez le recharger dans la mémoire, il y a une fonction qui a utilisé munmap pour remettre la structure de données dans le tableau de chars. Puisqu'il possède des adresses virtuelles pour vos pointeurs, vous pouvez réutiliser votre structure de données. Cela signifie que vous pouvez créer une structure de données, la sauvegarder, la charger, la modifier à nouveau et la sauvegarder à nouveau.

1 votes

Cela fonctionne très bien, même pour les structures arborescentes imbriquées, bien que certaines modifications aient été nécessaires au code pour le faire compiler. Un include manquant pour 'time.h' et un typedef présumé pour ushort qui n'est pas un standard du langage.

0 votes

Cependant, il ne gère pas les tableaux de pointeurs, de sorte qu'une structure de graphe qui en contient n'est pas sérialisée correctement, seul le premier pointeur est sérialisé.

4voto

quinmars Points 4241

Vous pouvez jeter un coup d'œil sur eet . Une bibliothèque du projet enlightenment pour stocker les types de données C (y compris les structures imbriquées). Bien que presque toutes les librairies du projet enlightenment soient en état pre-alpha, eet est déjà publié. Je ne suis pas sûr, cependant, qu'elle puisse gérer les références circulaires. Probablement pas.

3voto

gngrwzrd Points 740

Vous devriez consulter gwlib. Le sérialiseur/désérialiseur est très complet et il existe de nombreux tests à consulter. http://gwlib.com/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X