Serializar estruturas de dados em C

Eu gostaria de uma biblioteca C que pode serializar minhas estruturas de dados para o disco e carregá-las novamente mais tarde. Deve aceitar estruturas aninhadas arbitrariamente, possivelmente com referências circulares.

Eu presumo que essa ferramenta precisaria de um arquivo de configuração descrevendo minhas estruturas de dados. A biblioteca tem permissão para usar a geração de código, embora eu tenha quase certeza de que é possível fazer isso sem ela.

Note que não estou interessado em portabilidade de dados. Eu gostaria de usá-lo como um cache, para que eu possa confiar no ambiente que não está mudando.

Obrigado.


Resultados

Alguém sugeriu que o Tpl é uma biblioteca impressionante, mas acredito que ele não faça charts de objects arbitrários, como uma tree de nós, cada um contendo dois outros nós.

Outro candidato é o Eet , que é um projeto do gerenciador de janelas do Enlightenment. Parece interessante, mas, novamente, parece não ter a capacidade de serializar estruturas aninhadas.

Confira o tpl . Na visão geral:

Tpl é uma biblioteca para serializar dados C. Os dados são armazenados em sua forma binária natural. A API é pequena e tenta ficar “fora do caminho”. Comparado ao uso de XML, o tpl é mais rápido e mais fácil de usar em programas em C. O Tpl pode serializar muitos tipos de dados C, incluindo estruturas.

Eu sei que você está pedindo por uma biblioteca. Se você não consegue encontrar um (:: boggle ::, você acha que este foi um problema resolvido!), Aqui está um esboço para uma solução:

Você deve ser capaz de escrever um gerador de código [1] para serializar trees / charts sem pré-processamento (tempo de execução) de forma bastante simples.

Você precisará analisar a estrutura do nó ( typedef handling?) E gravar os valores de dados incluídos de maneira direta, mas trate os pointers com algum cuidado.

  • Para o ponteiro para outros objects (por exemplo, char *name; ) que você sabe que são referenciados individualmente, é possível serializar os dados de destino diretamente.

  • Para objects que possam ser referenciados multiplamente e para outros nós da sua tree, você terá que representar a estrutura do ponteiro. Cada object recebe um número de serialização, que é o que está escrito no lugar do ponteiro. Manter uma estrutura de conversão entre a posição atual da memory e o número de serialização. Ao encontrar um ponteiro, veja se já está atribuído um número, se não, dê um e enfileire esse object para serialização.

A leitura de volta também requer uma etapa de tradução node – # / memory-location, e pode ser mais fácil em duas etapas: regenerar os nós com os números de nós nos slots de ponteiro (ponteiro ruim, ser avisado) para descobrir onde cada nó Coloque, em seguida, andar a estrutura novamente consertando os pointers.

Eu não sei nada sobre o tpl, mas você pode ser capaz de passar por cima dele.


O formato em disco / rede provavelmente deve ser enquadrado com algumas informações de tipo. Você precisará de um esquema de manuseio de nomes.


[1] ROOT usa este mecanismo para fornecer suporte de serialização muito flexível em C ++.


Adição tardia: Ocorre-me que isso nem sempre é tão fácil quanto eu impliquei acima. Considere a seguinte declaração (inventada e mal concebida):

 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 suponha que nós iniciamos a saída de struct saved_setup items para que mask_name aponte para mask_list[foo].mask_name .

Quando vamos para serializar os dados, o que fazemos com struct saved_setup.mask_name ?

Você precisará tomar cuidado ao projetar suas estruturas de dados e / ou trazer alguma inteligência específica de caso para o processo de serialização.

Esta é minha solução. Ele usa minha própria implementação de chamadas de sistema malloc, free e mmap, munmap. Siga os códigos de exemplo fornecidos. Ref: http://amscata.blogspot.com/2013/02/serialize-your-memory.html

Na minha abordagem eu crio um array char como meu próprio espaço de RAM. Depois, há funções para alocar a memory e liberá-las. Depois de criar a estrutura de dados, usando o mmap , escrevo a matriz char em um arquivo.

Sempre que você quiser carregá-lo de volta para a memory, há uma function que usou munmap para colocar a estrutura de dados novamente no array char. Como ele possui endereços virtuais para seus pointers, você pode reutilizar sua estrutura de dados. Isso significa que você pode criar uma estrutura de dados, salvá-la, carregá-la, editá-la novamente e salvá-la novamente.

Você pode dar uma olhada no eet . Uma biblioteca do projeto de iluminação para armazenar tipos de dados C (incluindo estruturas aninhadas). Embora quase todas as libs do projeto de esclarecimento estejam em estado pré-alfa, eet já está liberado. Não tenho certeza, no entanto, se ele pode lidar com referências circulares. Provavelmente não.

você deve fazer o checkout do gwlib. o serializador / desserializador é extenso. e existem testes extensivos disponíveis para analisar. http://gwlib.com/

Eu estou supondo que você está falando sobre o armazenamento de uma estrutura de gráfico, se não, em seguida, desconsidere …

Se você está armazenando um gráfico, eu pessoalmente acho que a melhor idéia seria implementar uma function que converta seu gráfico em uma matriz de adjacência. Você pode, então, criar uma function que converta uma matriz de adjacência na estrutura de dados do seu gráfico.

Isso tem três benefícios (que podem ou não ser importantes em seu aplicativo):

  • matriz de adjacência é uma maneira muito natural de criar e armazenar um gráfico
  • Você pode criar uma matriz de adjacência e importá-las para seus aplicativos
  • Você pode armazenar e ler seus dados de maneira significativa.

Eu usei esse método durante um projeto de CS e é definitivamente como eu faria isso novamente.

Você pode ler mais sobre a matriz de adjacência aqui: http://en.wikipedia.org/wiki/Modified_adjacency_matrix

Outra opção é o Avro C , uma implementação do Apache Avro em C.

Em teoria, o YAML deve fazer o que quiser http://code.google.com/p/yaml-cpp/

Por favor, deixe-me saber se isso funciona para você.

Aqui está um exemplo usando a biblioteca Binn (minha criação):

  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 você não quiser usar strings como chaves, você pode usar um binn_map que usa números inteiros como chaves.

Também há suporte para listas, e todas essas estruturas podem ser aninhadas:

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