2009-04-22 12 views
6

Come posso fare qualcosa di simile (solo un esempio):Come creare e leggere dinamicamente le strutture in C?

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

così che ho potuto caricare e utilizzare un'istanza struct "dall'esterno" (all'indirizzo addressOfMyStruct) con la struttura data qui?

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

Vorrei anche essere in grado di creare istanze struct in modo dinamico in questo modo.

Spero sia chiaro cosa voglio fare. So che C/Invoke è in grado di farlo, ma esiste una libreria separata per farlo?

+0

A proposito, l'API era solo un esempio. Non ha bisogno di essere esattamente la stessa API. – user94405

risposta

6

In realtà la dimostrazione del codice per rendere questo lavoro in C è un po 'troppo complicata per un post SO. Ma spiegare il concetto di base è fattibile.

Quello che stai veramente creando qui è un sistema di sacchetti di proprietà con modelli. L'unica cosa di cui avrai bisogno per continuare a farlo è una struttura assiociativa come un tavolo di hash. Direi di andare con std :: map ma hai accennato che si trattava solo di una soluzione C. Per il gusto della discussione, supporterò che tu abbia una sorta di tabella hash disponibile.

La chiamata "create_struct" dovrà restituire una struttura che contiene un puntatore a una tabella hash che rende const char* essenzialmente un size_t. Questa mappa definisce ciò di cui hai bisogno per creare una nuova istanza della struttura.

Il metodo "insance" creerà essenzialmente un nuovo hashtable con un numero uguale di membri come modello hashtable. Lanciamo una pigra valutazione dalla finestra per un secondo e assumiamo che crei tutti i membri in anticipo. Il metodo dovrà eseguire il looping del modello hashtable aggiungendo un membro per ogni voce e mallociando un blocco di memoria della dimensione specificata.

L'implementazione di instance_get_member effettuerà semplicemente una ricerca nella mappa per nome. Tuttavia, la firma e il modello di utilizzo dovranno cambiare. C non supporta i modelli e deve scegliere un tipo di reso comune che possa rappresentare tutti i dati. In questo caso dovrai scegliere void* poiché è così che sarà necessario memorizzare la memoria.

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

Si può fare di questo un po 'meglio con l'aggiunta di una macro envil per simulare modelli

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

Grazie, non sembra così difficile. Tuttavia, è possibile che mi imbatto in problemi con padding o qualcosa del genere? – user94405

+0

@frw, non dovresti perché stai usando malloc per allocare spazio per i dati della struttura. Dal momento che è memorizzato in un dizionario, dovrebbe esserci una allocazione per membro. I problemi di riempimento si verificano solo se li si riempie all'interno di un blocco di memoria contiguo. Potresti adottare questo approccio anche se lo eviterei, in particolare a causa di motivi di imballaggio;) – JaredPar

+0

Bene, leggerò un po 'di imballaggio e vedrò cosa farò. Tuttavia, l'uso di C/Invoke sarebbe la soluzione più semplice. Grazie per ora! – user94405

1

sei andato così lontano che definiscono il problema che tutto quello che resta è un po' di (un po 'complicato in alcune parti) implementazione. Hai solo bisogno di tenere traccia delle informazioni:

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; 

Poi create_struct() alloca la memoria per meta_struct e inizializzata a 0, e add_struct_member() fa un alloc()/realloc() su my_struct.fields e incrementi my_struct.num_fields. Il resto segue la stessa vena.

Si desidera anche un union in meta_struct_field per contenere i valori effettivi nelle istanze.

0

Ho fatto un po 'di questo molto tempo fa.

Il modo in cui l'ho fatto è stato generare un codice contenente la definizione della struct, oltre a tutte le routine per accedervi e quindi compilarlo e collegarlo in una DLL "al volo", quindi caricare dinamicamente tale DLL.

+0

Purtroppo non è un'opzione per me. Grazie comunque :) – user94405

Problemi correlati