Reputation: 13514
My application is written in C. I have a module that uses some data from a certain given global structure. I now have to extend the module to optionally work against a different given global structure, which basically provides the same fields (as far as my module is concerned), but under different names.
Here's a car analogy to hopefully make my problem clearer. I've got these two global structures I have no control over.
struct {
unsigned char manufacturer_id;
unsigned short top_speed;
} Car;
struct {
RGB_t color;
unsigned short topSpeed;
unsigned char mfr;
} Automobile;
Let's say my Car Manager module uses information from Automobile. E.g.,
const char *car_manager__get_manufacturer_name(car_manager_t *self)
{
return self->manufacturers[Automobile.mfr];
}
I'd like to extend Car Manager to optionally (perhaps decided by a flag in the car_manager_t instance) use the same information from Car, so the above function would return self->manufacturers[Car.manufacturer_id]
. I don't want to duplicate any logic in the module while adding this functionality.
I assume I'll have to put an interface on the access to the global structures. Any suggestions on how to do that?
Upvotes: 2
Views: 132
Reputation: 30445
I would define functions for getting the needed values, and pass pointers to the functions. You could even pass a struct which contains the needed function pointers.
struct Interface {
unsigned char (*manufacturer)(void);
unsigned short (*top_speed)(void);
}
struct Interface CarInterface = {&Car_manufacturer, &Car_top_speed};
struct Interface AutoInterface = {&Auto_manufacturer, &Auto_top_speed};
const char *car_manager__get_manufacturer_name(car_manager_t *self, Interface i)
{
return self->manufacturers[(*i.manufacturer)()];
}
I haven't written any C for a long time; please correct my syntax if necessary!
Upvotes: 1
Reputation: 19022
This is just the first solution that came to my mind, but one way to go about it might be to generalize your module to make it configurable so you can tell it how to look up the fields.
It's been a while since I coded in C, so consider this pseudo code ;)
The two structures:
/* Struct layout 1 */
struct {
float x; /*aka foo*/
float y; /*aka bar*/
float z; /*aka baz*/
} entity_type1;
/* Struct layout 2 */
struct {
float c; /*aka baz*/
float a; /*aka foo*/
float b; /*aka bar*/
} entity_type2;
The module:
struct {
int foo_index;
int bar_index;
int baz_index;
} fields_definition;
/* Private configuration */
fields_definition entity_fields;
/* Private getters */
float foo(void * entity) {
return *(float*)(entity_ptr + entity_fields.foo_index);
}
float bar(void * entity) {
return *(float*)(entity_ptr + entity_fields.bar_index);
}
/* Private setters */
void baz(void * entity, float value) {
*(float*)(entity_ptr + entity_fields.baz_index) = value; /* Legal?? */
}
/* Exported/Public function for setup */
void configure(fields_definition entity_fields_config){
entity_fields = entity_fields_config;
}
/* Normal exported/public function for usage */
void some_operation(void * entity) {
baz(entity, foo(entity) + bar(entity));
}
Usage:
/* Initialize... */
fields_definition for_type1 = {0,4,8};
fields_definition for_type2 = {4,8,0};
configure(for_type2);
/* ... and use */
entity_type2 e;
some_operation(&e);
Setting up the field_definition(s) could also be done by something similar to
entity_type2 t2;
fields_definition for_type2 = {
&(t2.a)-&t2,
&(t2.b)-&t2,
&(t2.c)-&t2
};
(Again, it's been a while, so I don't remember exactly how this would be done.) I believe some compilers have a built in function for getting the field offset in a struct, which would be cleaner but less portable.
Upvotes: 0
Reputation: 5456
I don't know exactly what do you need, but note that if you have an union, that contain several structs that begin with the same types, you can access those types equally through all the structs. for example, if you have:
union bla {
struct {
int a;
char b;
float *c;
} s1;
struct {
int r;
char c;
float *j;
short s;
} s2;
int i;
} un;
Then un.s1.a
,un.s2.r
,un.i
are the same, and so on un.s1.c==un.s2.j
Also, consider moving to C++
(and overload functions for your structs)
Upvotes: 0