2012-01-26 3 views
2

Мое приложение написано на C. У меня есть модуль, который использует некоторые данные из определенной , приведенной в глобальной структуре. Теперь я должен расширить модуль, чтобы, возможно, работать против другой заданной глобальной структуры, которая в основном предоставляет те же поля (что касается моего модуля), но под разными именами.Инкапсулирующий доступ к аналогичным структурам

Вот аналогий автомобилей, надеюсь, сделать мою проблему более ясной. У меня эти две глобальные структуры, над которыми я не контролирую.

struct { 
    unsigned char manufacturer_id; 
    unsigned short top_speed; 
} Car; 

struct { 
    RGB_t color; 
    unsigned short topSpeed; 
    unsigned char mfr; 
} Automobile; 

Скажем, мой модуль Автоменеджмента использует информацию от Automobile. НАПРИМЕР,

const char *car_manager__get_manufacturer_name(car_manager_t *self) 
{ 
    return self->manufacturers[Automobile.mfr]; 
} 

Я хотел бы расширить Car Manager для необязательно (возможно решается флагом в car_manager_t, например) используют ту же самую информацию от автомобиля, поэтому данная функция будет возвращать self->manufacturers[Car.manufacturer_id]. Я не хочу дублировать логику в модуле, добавляя эту функциональность.

Я предполагаю, что мне нужно будет установить интерфейс для доступа к глобальным структурам. Любые предложения о том, как это сделать?

+0

Вы можете быть более конкретными? – nmichaels

ответ

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 в течение длительного времени; пожалуйста, исправьте мой синтаксис, если необходимо!

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++ (и перегрузки функций для ваших структур)

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 
}; 

(Опять же, это было какое-то время, так что я не помню точно, как это будет сделано.) Я считаю, что некоторые компиляторы имеют встроенная функция для получения смещения поля в структуре, которая будет более чистой, но менее переносной.

Смежные вопросы