Serializzare strutture dati in C

Mi piacerebbe una libreria C in grado di serializzare le mie strutture dati su disco e quindi caricarle di nuovo in seguito. Dovrebbe accettare strutture annidate arbitrariamente, possibilmente con riferimenti circolari.

Presumo che questo strumento abbia bisogno di un file di configurazione che descriva le mie strutture di dati. La libreria può utilizzare la generazione del codice, anche se sono abbastanza sicuro che sia ansible farlo senza di esso.

Nota Non sono interessato alla portabilità dei dati. Mi piacerebbe usarlo come cache, quindi posso contare sull’ambiente che non cambia.

Grazie.


risultati

Qualcuno ha suggerito Tpl che è una libreria fantastica, ma credo che non faccia grafici di oggetti arbitrari, come un albero di Nodi che contengono ciascuno altri due Nodi.

Un altro candidato è Eet , che è un progetto del gestore di windows di Enlightenment. Sembra interessante ma, di nuovo, sembra non avere la possibilità di serializzare le strutture annidate.

Dai un’occhiata a TPL . Dalla panoramica:

Tpl è una libreria per serializzare i dati C. I dati sono memorizzati nella sua forma binaria naturale. L’API è piccola e cerca di rimanere “fuori strada”. Rispetto all’utilizzo di XML, tpl è più veloce e più facile da usare nei programmi C. Tpl può serializzare molti tipi di dati C, incluse le strutture.

So che stai chiedendo una biblioteca. Se non riesci a trovarne uno (:: boggle ::, penseresti che fosse un problema risolto!), Ecco uno schema per una soluzione:

Dovresti essere in grado di scrivere un generatore di codice [1] per serializzare alberi / grafici senza pre-elaborazione (in fase di esecuzione) abbastanza semplicemente.

Dovrai analizzare la struttura del nodo (gestione typedef ?) E scrivere i valori dei dati inclusi in modo diretto, ma trattare i puntatori con un po ‘di attenzione.

  • Per il puntatore ad altri oggetti (es char *name; ) che sai essere referenziato singolarmente, puoi serializzare direttamente i dati di destinazione.

  • Per oggetti che potrebbero essere moltiplicati come riferimento e per altri nodes del tuo albero dovrai rappresentare la struttura del puntatore. Ad ogni object viene assegnato un numero di serializzazione, che è ciò che è scritto al posto del puntatore. Mantenere una struttura di traduzione tra la posizione di memoria corrente e il numero di serializzazione. Nell’incontrare un puntatore, vedere se è già assegnato un numero, in caso contrario, dargli uno e accodare l’object per la serializzazione.

La lettura richiede anche un passaggio di conversione nodo – # / posizione di memoria, e potrebbe essere più semplice da eseguire in due passaggi: rigenerare i nodes con i numeri di nodo negli slot del puntatore (puntatore errato, attenzione) per scoprire dove viene assegnato ciascun nodo metti, quindi cammina nuovamente la struttura fissando i puntatori.

Non so nulla di TPL, ma potresti essere in grado di portarlo a termine.


Il formato su disco / rete dovrebbe probabilmente essere incorniciato con alcune informazioni di tipo. Avrai bisogno di uno schema per manomettere il nome.


[1] ROOT utilizza questo meccanismo per fornire un supporto di serializzazione molto flessibile in C ++.


Aggiunta tardiva: Mi sembra che questo non sia sempre così facile come ho implicato sopra. Considera la seguente dichiarazione (inventata e mal progettata):

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

e assumiamo che struct saved_setup elementi struct saved_setup modo che mask_name punti a mask_list[foo].mask_name .

Quando andiamo a serializzare i dati, cosa facciamo con struct saved_setup.mask_name ?

Avrai bisogno di fare attenzione nel progettare le tue strutture dati e / o portare qualche intelligenza specifica del caso al processo di serializzazione.

Questa è la mia soluzione. Usa la mia propria implementazione di malloc, free e mmap, chiamate di sistema munmap. Segui i codici di esempio indicati. Rif: http://amscata.blogspot.com/2013/02/serialize-your-memory.html

Nel mio approccio, creo un array di caratteri come spazio RAM personale. Poi ci sono funzioni per allocare la memoria e liberarle. Dopo aver creato la struttura dati, usando mmap , scrivo il char array su un file.

Ogni volta che vuoi caricarlo di nuovo nella memoria, c’è una funzione che usa munmap per rimettere la struttura dei dati nel char array. Dal momento che dispone di indirizzi virtuali per i tuoi indicatori, puoi riutilizzare la tua struttura dati. Ciò significa che puoi creare una struttura dati, salvarla, caricarla, modificarla di nuovo e salvarla di nuovo.

Puoi dare un’occhiata a eet . Una libreria del progetto di illuminazione per archiviare i tipi di dati C (comprese le strutture nidificate). Sebbene quasi tutte le librerie del progetto di illuminazione siano in stato pre-alfa, eet è già stato rilasciato. Non sono sicuro, tuttavia, se può gestire riferimenti circolari. Probabilmente no.

dovresti dare un’occhiata a gwlib. il serializzatore / deserializzatore è esteso. e ci sono test approfonditi disponibili per guardare. http://gwlib.com/

Suppongo che tu stia parlando dell’archiviazione di una struttura di grafici, se non lo fai, allora non prendere in considerazione …

Se memorizzi un grafico, personalmente penso che l’idea migliore sarebbe implementare una funzione che converta il tuo grafico in una matrice di adiacenza. È quindi ansible creare una funzione che converta una matrice di adiacenza nella struttura dei dati del grafico.

Questo ha tre vantaggi (che possono o non possono importare nella tua applicazione):

  • la matrice di adiacenza è un modo molto naturale per creare e memorizzare un grafico
  • È ansible creare una matrice di adiacenza e importarli nelle applicazioni
  • È ansible memorizzare e leggere i dati in modo significativo.

Ho usato questo metodo durante un progetto CS ed è sicuramente come lo farei di nuovo.

Puoi leggere ulteriori informazioni sulla matrice di adiacenza qui: http://en.wikipedia.org/wiki/Modified_adjacency_matrix

Un’altra opzione è Avro C , un’implementazione di Apache Avro in C.

In teoria, YAML dovrebbe fare ciò che vuoi http://code.google.com/p/yaml-cpp/

Per favore fatemi sapere se funziona per voi.

Ecco un esempio che utilizza la libreria Binn (la mia creazione):

  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); 

Se non vuoi usare stringhe come chiavi puoi usare una binn_map che usa numeri interi come chiavi.

C’è anche il supporto per le liste e tutte queste strutture possono essere annidate:

  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);