Je voudrais une bibliothèque C qui puisse sérialiser mes structures de données sur disque, puis les recharger plus tard. Il doit accepter des structures imbriquées arbitrairement, éventuellement avec des références circulaires.
Je suppose 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, bien que je sois assez sûr qu'il est possible de le faire sans elle.
Remarque Je ne suis pas intéressé par la portabilité des données. Je voudrais l'utiliser comme cache, donc je peux compter sur un environnement qui 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 de graphiques 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. Semble intéressant mais, encore une fois, ne semble pas avoir la possibilité de sérialiser les structures imbriquées.
Découvrez tpl . De l'aperçu:
Tpl est une bibliothèque de sérialisation des données C. Les données sont stockées sous 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. Tpl peut sérialiser de nombreux types de données C, y compris des structures.
Je sais que tu demandes une bibliothèque. Si vous n'en trouvez pas (:: boggle ::, vous penseriez que ce problème a été résolu!), Voici un aperçu d'une solution:
Vous devriez pouvoir écrire un générateur de code [1] pour sérialiser les arbres/graphiques sans pré-traitement (au moment de l'exécution) assez simplement.
Vous devrez analyser la structure du nœud (typedef
manipulation?), Et écrire les valeurs de données incluses de façon directe, mais traitez les pointeurs avec un certain soin.
Pour le pointeur vers d'autres objets (c'est-à-dire char *name;
) que vous savez sont référencés individuellement, vous pouvez sérialiser directement les données cibles.
Pour les objets qui peuvent être multipliés par référence et pour les autres nœuds de votre arbre, vous devrez représenter la structure du pointeur. Chaque objet reçoit un numéro de sérialisation, qui est écrit à la place du pointeur. Maintenir une structure de traduction entre la position actuelle de la mémoire et le numéro de série. En rencontrant un pointeur, voyez si un numéro lui est déjà attribué, sinon, attribuez-lui un et mettez cet objet en file d'attente pour la sérialisation.
La lecture nécessite également une étape de conversion noeud - #/emplacement mémoire, et pourrait être plus facile à faire en deux passes: régénérez les noeuds avec les numéros de noeud dans les emplacements de pointeur (mauvais pointeur, soyez averti) pour savoir où obtient chaque noeud mettre, puis marcher à nouveau la structure en fixant les pointeurs.
Je ne sais rien de tpl, mais vous pourrez peut-être vous y greffer.
Le format sur disque/réseau doit probablement être encadré avec des informations de type. Vous aurez besoin d'un schéma de gestion de noms.
[1] ROOT 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érez la déclaration suivante (artificielle 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
éléments afin que mask_name
pointe sur mask_list[foo].mask_name
.
Lorsque nous allons sérialiser les données, que faisons-nous avec struct saved_setup.mask_name
?
Vous devrez prendre soin de concevoir vos structures de données et/ou apporter des informations spécifiques au cas dans le processus de sérialisation.
C'est ma solution. Il utilise ma propre implémentation d'appels système malloc, free et mmap, munmap. Suivez les exemples de codes donnés. Réf: http://amscata.blogspot.com/2013/02/serialize-your-memory.html
Dans mon approche, je crée un tableau de caractères comme mon propre RAM espace. Ensuite, il y a des fonctions pour allouer la mémoire et les libérer. Après avoir créé la structure de données, en utilisant mmap
, J'écris le tableau char dans un fichier.
Chaque fois que vous souhaitez le recharger dans la mémoire, il existe une fonction qui utilise munmap
pour remettre la structure de données dans le tableau char. Puisqu'il a 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, l'enregistrer, la charger, la modifier à nouveau et la sauvegarder à nouveau.
Vous pouvez jeter un œ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 bibliothèques du projet Enlightenment soient en état pré-alpha, eet est déjà publié. Je ne suis pas sûr, cependant, s'il peut gérer les références circulaires. Probablement pas.
vous devriez vérifier gwlib. le sérialiseur/désérialiseur est vaste. et de nombreux tests sont disponibles. http://gwlib.com/
Je suppose que vous parlez de stocker une structure de graphe, sinon ne tenez pas compte ...
Si vous stockez un graphique, je pense personnellement que la meilleure idée serait d'implémenter une fonction qui convertit votre graphique en une matrice d'adjacence. Vous pouvez ensuite créer une fonction qui convertit une matrice d'adjacence en votre structure de données de graphique.
Cela présente trois avantages (qui peuvent ou non être importants dans votre application):
J'ai utilisé cette méthode lors d'un projet CS et c'est définitivement la façon dont je le referais.
Vous pouvez en savoir plus sur la matrice d'adjacence ici: http://en.wikipedia.org/wiki/Modified_adjacency_matrix
Une autre option est Avro C , une implémentation de Apache Avro en C.
Voici un exemple utilisant la bibliothèque Binn (ma création):
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);
Si vous ne souhaitez pas utiliser des chaînes comme clés, vous pouvez utiliser un binn_map qui utilise des entiers comme clés.
Il existe également un support pour les listes, et toutes ces structures peuvent être imbriquées:
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);
En théorie, YAML devrait faire ce que vous voulez http://code.google.com/p/yaml-cpp/
Veuillez me faire savoir si cela fonctionne pour vous.