我的应用程序是用C语言编写的。我有一个模块,它使用来自某个给定全局结构的一些数据。我现在必须扩展模块以选择性地针对不同的给定全局结构进行操作,该结构基本上提供相同的字段(就我的模块而言),但名称不同。
这是一个汽车类比,希望能让我的问题更加清晰。我有两个我无法控制的全局结构。
struct {
unsigned char manufacturer_id;
unsigned short top_speed;
} Car;
struct {
RGB_t color;
unsigned short topSpeed;
unsigned char mfr;
} Automobile;
假设我的汽车经理模块使用来自汽车的信息。如,
const char *car_manager__get_manufacturer_name(car_manager_t *self)
{
return self->manufacturers[Automobile.mfr];
}
我想将Car Manager扩展为可选(可能由car_manager_t实例中的标志决定)使用来自Car的相同信息,因此上述函数将返回self->manufacturers[Car.manufacturer_id]
。在添加此功能时,我不想复制模块中的任何逻辑。
我假设我必须在访问全局结构时设置接口。有关如何做到这一点的任何建议吗?
答案 0 :(得分:1)
我将定义用于获取所需值的函数,并将指针传递给函数。你甚至可以传递一个包含所需函数指针的结构。
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)()];
}
我很长时间没有写过任何C语言;如有必要,请更正我的语法!
答案 1 :(得分:0)
我不确切知道你需要什么,但请注意,如果你有一个包含几个以相同类型开头的结构的联合,你可以通过所有结构同等地访问这些类型。例如,如果你有:
union bla {
struct {
int a;
char b;
float *c;
} s1;
struct {
int r;
char c;
float *j;
short s;
} s2;
int i;
} un;
然后un.s1.a
,un.s2.r
,un.i
是相同的,依此类推un.s1.c==un.s2.j
另外,请考虑转到C++
(以及结构的重载函数)
答案 2 :(得分:0)
这只是我想到的第一个解决方案,但其中一种方法可能是概括您的模块以使其可配置,以便您可以告诉它如何查找字段。
自从我用C编码以来已经有一段时间了,所以请考虑这个伪代码;)
这两种结构:
/* 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;
模块:
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));
}
用法:
/* 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);
设置field_definition也可以通过与
类似的方式完成entity_type2 t2;
fields_definition for_type2 = {
&(t2.a)-&t2,
&(t2.b)-&t2,
&(t2.c)-&t2
};
(同样,它已经有一段时间了,所以我不记得究竟是怎么做的。)我相信一些编译器有一个内置函数来获取结构中的字段偏移量,这样会更清晰但更不便携