6 Stimmen

Wie kann man in C dynamisch Strukturen erstellen und lesen?

Wie kann ich so etwas machen (nur ein Beispiel):

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

Damit ich eine struct-Instanz "von außen" laden und verwenden kann (unter der Adresse addressOfMyStruct ) mit der hier angegebenen Struktur?

any_struct_instance *instance = instance(my_struct, addressOfMyStruct);
int a = instance_get_member(instance, "a");
float b = instance_get_member(instance, "b");

Ich möchte auch in der Lage sein, struct-Instanzen auf diese Weise dynamisch zu erstellen.

Ich hoffe, es ist klar, was ich tun will. Ich weiß, dass C/Aufruf ist dazu in der Lage, aber gibt es dafür eine eigene Bibliothek?

6voto

JaredPar Punkte 699699

Die eigentliche Demonstration des C-Codes ist ein bisschen zu kompliziert für einen SO-Beitrag. Aber das Grundkonzept zu erklären, ist machbar.

Was Sie hier wirklich schaffen, ist ein schablonenhaftes Eigenschaftssacksystem. Die eine Sache, die Sie brauchen eine Menge, um dies zu halten, ist einige assoziative Struktur wie eine Hashtabelle. Ich würde sagen, gehen Sie mit std::map, aber Sie erwähnt dies war eine C nur Lösung. Für die Diskussion gehe ich einfach davon aus, dass Sie eine Art von Hashtable zur Verfügung haben.

Der "create_struct"-Aufruf muss eine Struktur zurückgeben, die einen Zeiger auf eine Hashtabelle enthält, so dass const char* im Wesentlichen zu einer size_t. Diese Zuordnung definiert, was Sie benötigen, um eine neue Instanz der Struktur zu erstellen.

Die "insance"-Methode wird im Wesentlichen eine neue Hashtabelle mit der gleichen Anzahl von Mitgliedern wie die Vorlage Hashtabelle erstellen. Werfen wir die faule Vermutung für eine Sekunde aus dem Fenster und nehmen an, dass Sie alle Mitglieder im Voraus erstellen. Die Methode muss eine Schleife über die Vorlage hashtable Hinzufügen eines Mitglieds für jeden Eintrag und malloc'ing ein Speicherchunk der angegebenen Größe.

Die Implementierung von instance_get_member führt einfach eine Suche in der Map nach Namen durch. Die Signatur und das Verwendungsmuster müssen jedoch geändert werden. C unterstützt keine Templates und muss einen allgemeinen Rückgabetyp wählen, der alle Daten repräsentieren kann. In diesem Fall müssen Sie Folgendes wählen void* da der Speicher auf diese Weise gespeichert werden muss.

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

Sie können dies noch etwas verbessern, indem Sie ein envil-Makro hinzufügen, um Vorlagen zu simulieren

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

1voto

dwc Punkte 22998

Sie haben das Problem so weit definiert, dass nur noch die (teilweise etwas knifflige) Umsetzung übrig ist. Sie müssen nur noch die Informationen im Auge behalten:

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;

Dann create_struct() weist Speicher zu für meta_struct und auf 0 initialisiert, und add_struct_member() macht ein alloc() / realloc() sur my_struct.fields und Inkremente my_struct.num_fields . Der Rest folgt in der gleichen Art und Weise.

Sie benötigen auch eine union en meta_struct_field um tatsächliche Werte in Instanzen zu halten.

0voto

Mike Dunlavey Punkte 39339

Das habe ich vor langer Zeit schon einmal gemacht.

Die Art und Weise, wie ich es gemacht habe, bestand darin, Code zu generieren, der die Strukturdefinition sowie alle Routinen für den Zugriff darauf enthielt, und diesen dann "on the fly" zu kompilieren und in eine DLL zu verlinken und diese DLL dann dynamisch zu laden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X