2009-04-22 11 views
6

Comment puis-je faire quelque chose comme ça (juste un exemple):Comment créer dynamiquement et lire des structures en C?

any_struct *my_struct = create_struct(); 
add_struct_member(my_struct, "a", int_member); 
add_struct_member(my_struct, "b", float_member); 

pour que je puisse charger et utiliser une instance de struct « de l'extérieur » (à l'adresse addressOfMyStruct) avec la structure donnée ici? J'aimerais aussi pouvoir créer dynamiquement des instances struct de cette façon.

J'espère que ce que je veux faire est clair. Je sais que C/Invoke est capable de le faire, mais y at-il une bibliothèque séparée pour le faire?

+0

Il n'a pas besoin d'être exactement la même API. – user94405

Répondre

6

Faire réellement la démonstration du code pour que cela fonctionne en C est un peu trop impliqué pour un post SO. Mais expliquer le concept de base est faisable.

Ce que vous créez vraiment ici est un système de sac de propriété de modèle. La seule chose dont vous aurez besoin pour continuer est une structure assiociative comme une table de hachage. Je dirais aller avec std :: map, mais vous avez mentionné que c'était une solution C seulement. Par souci de discussion, je vais supposer que vous avez une sorte de hashtable disponible. L'appel "create_struct" devra renvoyer une structure qui contient un pointeur sur une hashtable qui rend const char* essentiellement à size_t. Cette carte définit ce dont vous avez besoin pour créer une nouvelle instance de la structure.

La méthode "insance" créera essentiellement une nouvelle table de hachage avec un nombre égal de membres comme table de hachage de gabarit. Laissons l'évasion paresseuse à la fenêtre pendant une seconde et supposons que vous créez tous les membres à l'avant. La méthode devra faire une boucle sur la table de hachage du gabarit en ajoutant un membre pour chaque entrée et en plaçant un morceau de mémoire de la taille spécifiée.

L'implémentation de instance_get_member fera simplement une recherche dans la carte par son nom. La signature et le modèle d'utilisation devront cependant changer. C ne prend pas en charge les modèles et doit choisir un type de retour commun pouvant représenter toutes les données. Dans ce cas, vous devrez choisir void* car c'est ainsi que la mémoire devra être stockée.

void* instance_get_member(any_struct_instance* inst, const char* name); 

Vous pouvez faire un peu mieux en ajoutant une macro envil pour simuler des modèles

#define instance_get_member2(inst, name, type) \ 
    *((type*)instance_get_member((inst),(name))) 
... 
int i = instance_get_member2(pInst,"a", int); 
+0

Merci, cela ne semble pas si difficile. Cependant, est-il possible que je tombe sur des problèmes de rembourrage ou quelque chose comme ça? – user94405

+0

@frw, vous ne devriez pas parce que vous utilisez malloc pour allouer de l'espace pour les données struct. Comme il est stocké dans un dictionnaire, il devrait y avoir une allocation par membre. Les problèmes de remplissage ne se produisent réellement que si vous les placez dans un bloc de mémoire contigu. Vous pourriez adopter cette approche même si je l'évite, en particulier pour des raisons d'emballage;) – JaredPar

+0

Bien, je vais lire un peu sur l'emballage et voir ce que je vais faire. Cependant, utiliser C/Invoke serait la solution la plus simple. Merci pour maintenant! – user94405

1

Vous êtes allé définir jusqu'à présent le problème que tout ce qui reste est un peu (un peu difficile à certaines parties) mise en œuvre. Vous avez juste besoin de garder une trace des informations:

typedef struct { 
    fieldType type; 
    char  name[NAMEMAX]; 
    /* anything else */ 
} meta_struct_field; 
typedef struct { 
    unsigned   num_fields; 
    meta_struct_field *fields; 
    /* anything else */ 
} meta_struct; 

Puis create_struct() alloue de la mémoire meta_struct et initialisés à 0, et add_struct_member() fait un alloc()/realloc() sur my_struct.fields et incréments my_struct.num_fields. Le reste suit dans la même veine.

Vous aurez également besoin d'un union en meta_struct_field pour conserver les valeurs réelles dans les instances.

0

Je l'ai fait il y a longtemps.

La façon dont je l'ai fait était de générer du code contenant la définition de struct, plus toutes les routines pour y accéder et ensuite compiler et lier dans une DLL "à la volée", puis charger dynamiquement cette DLL. Par ailleurs, l'API était juste un exemple.

+0

Malheureusement, ce n'est pas une option pour moi. Merci quand même :) – user94405

Questions connexes