2012-01-26 45 views
2

我的應用程序是用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_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.aun.s2.run.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(S)也可以通過類似的東西可以做

entity_type2 t2; 
fields_definition for_type2 = { 
    &(t2.a)-&t2, 
    &(t2.b)-&t2, 
    &(t2.c)-&t2 
}; 

(再次,它已經有一段時間了,所以我不記得確切如何做到這一點做)。我相信一些編譯器可以一個內置函數,用於在結構中獲得字段偏移量,該函數將更乾淨但便攜性更低。