2009-04-22 17 views
6

¿Cómo puedo hacer algo por el estilo (es un ejemplo):¿Cómo crear y leer estructuras dinámicamente en C?

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

para que pudiera cargar y utilizar una instancia de estructura "desde el exterior" (en la dirección addressOfMyStruct) con la estructura dada aquí?

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

También me gustaría ser capaz de crear instancias de estructuras dinámicamente de esta manera.

Espero que esté claro lo que quiero hacer. Sé que C/Invoke es capaz de hacerlo, pero ¿hay una biblioteca separada para hacer eso?

+0

Por cierto, la API fue solo un ejemplo. No necesita ser exactamente la misma API. – user94405

Respuesta

6

En realidad, demostrar el código para hacer que esto funcione en C es demasiado complicado para una publicación SO. Pero explicar el concepto básico es factible.

Lo que realmente está creando aquí es un sistema de bolsa de propiedades con plantilla. Lo único que necesitará mucho para mantener esto en marcha es una estructura asistencial como una tabla hash. Yo diría que vaya con std :: map, pero mencionó que esta era una solución única de C. Por el bien de la discusión, voy a suponer que tienes algún tipo de hashtable disponible.

La llamada "create_struct" deberá devolver una estructura que contiene un puntero a una tabla hash que hace que const char* sea esencialmente un tamaño_t. Este mapa define lo que necesita para crear una nueva instancia de la estructura.

El método "insance" básicamente creará una nueva tabla hash con el mismo número de miembros que la plantilla hashtable. Permite arrojar evualation perezoso por la ventana por un segundo y asumir que crea todos los miembros por adelantado. El método deberá pasar por encima de la tabla hash de la plantilla para agregar un miembro para cada entrada y malloclar una porción de memoria del tamaño especificado.

La implementación de instance_get_member simplemente hará una búsqueda en el mapa por su nombre. Sin embargo, la firma y el patrón de uso deberán cambiar. C no admite plantillas y debe elegir un tipo de devolución común que pueda representar todos los datos. En este caso, deberá elegir void*, ya que así es como deberá almacenarse la memoria.

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

Puede hacer esto un poco mejor mediante la adición de una macro ENVIL para simular las plantillas

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

Gracias, eso suena no tan difícil. Sin embargo, ¿es posible que me tropiece con problemas con el relleno o algo así? – user94405

+0

@frw, no deberías hacerlo porque estás usando malloc para asignar espacio para los datos de estructura. Como está almacenado en un diccionario, debe haber una asignación por miembro. Los problemas de relleno solo surgen realmente si los está rellenando dentro de un bloque contiguo de memoria. Podrías tomar ese enfoque aunque lo evitaría, específicamente por razones de embalaje;) – JaredPar

+0

Bien, leeré un poco sobre el embalaje y veré qué voy a hacer. Sin embargo, usar C/Invoke sería la solución más simple. ¡Gracias por ahora! – user94405

1

Usted ha llegado al extremo que definen el problema de que todo lo que queda es un poco de (un poco difícil en algunas partes) implementación. Sólo se necesita para realizar un seguimiento de la información:

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; 

Entonces create_struct() asigna memoria para meta_struct e inicializado a 0, y add_struct_member() hace un alloc()/realloc() en my_struct.fields y los incrementos my_struct.num_fields. El resto sigue en la misma vena.

También querrá un union en meta_struct_field para mantener los valores reales en instancias.

0

Hice algo de esto hace mucho tiempo.

La forma en que lo hice fue generar código que contenía la definición de estructura, más todas las rutinas para acceder a él y compilarlo y vincularlo a una DLL "sobre la marcha", luego cargar esa DLL dinámicamente.

+0

Desafortunadamente esa no es una opción para mí. Gracias de cualquier manera :) – user94405