2016-06-10 2 views
2

Говорят, что у меня есть две различные структуры:массив над различными структурами

typedef struct { 
int a; 
int b; 
int c; 
int d; 
} struct_1; 

typedef struct { 
int a; 
int b; 
int e; 
int f; 
int g; 
int h; 
} struct_2; 

И что они используются аналогичным образом в двух разных алгоритма. То, что я попытаюсь сделать, - это заменить обе структуры, которые в основном разные, с динамическим массивом и использовать два перечисления для случаев, которые мне действительно нужны. Целью было бы сохранить разное имя полей структуры, а не использовать числа. Так что-то вроде:

typedef enum { 
a, 
b, 
c, 
d, 
num1_fields 
} struct_1_fields; 

typedef enum { 
a, 
b, 
e, 
f, 
g, 
h 
num1_fields 
} struct_2_fields; 

int *structure; 
if(case_1) { 
    structure = malloc(4*sizeof(int)); 
} else if(case_2) { 
    structure = malloc(6*sizeof(int)); 
} else { 
//something else 
} 

Однако, так как я бы повторно назначить тот же нумератор, компилятор не будет работать ... есть способ решить эту проблему?

+1

Переключение на C++ вариант? –

+0

Извините ... но нет XD. В противном случае я бы использовал его. – user8469759

+1

Вы можете извлечь общие члены в третий тип структуры, а затем использовать их для определения своих других структур: 'typedef struct {struct_3 shared_fields; int c, d; } struct_1; ... «Трудно сказать, может ли это решить вашу проблему. Что именно вы пытаетесь достичь? – melpomene

ответ

1

Вы можете использовать объектно-ориентированный подход на C:

#include <stdio.h> 
    #include <stdlib.h> 

    // forward declaration for virtual function table 
    struct vtable; 

    // base class 
    typedef struct { 
    struct vtable* tbl_; 
    } base; 

    // virtual function table 
    typedef struct vtable { 
    void(*method_for_algorithm_1_)(base* object); 
    void(*method_for_algorithm_2_)(base* object); 
    } vtable; 

    // algorithm 1 knowns only about base 
    void algorithm_1(base* p[], int size) { 
    for (int i = 0; i < size; i++) { 
     p[i]->tbl_->method_for_algorithm_1_(p[i]); 
    } 
    } 

    // algorithm 2 knowns only about base 
    void algorithm_2(base* p[], int size) { 
    for (int i = 0; i < size; i++) { 
     p[i]->tbl_->method_for_algorithm_2_(p[i]); 
    } 
    } 

    // struct1 is base 
    typedef struct { 
    base super_; 
    int a; 
    int b; 
    int c; 
    } struct1; 

    // struct2 is base 
    typedef struct { 
    base super_; 
    int a; 
    int b; 
    int c; 
    int d; 
    int e; 
    } struct2; 

    void struct1_method_for_algorithm1(base* object) { 
    struct1* s1 = (struct1*)object; 
    printf("struct1_method_for_algorithm1: %d %d %d\n", s1->a, s1->b, s1->c); 
    } 
    void struct1_method_for_algorithm2(base* object) { 
    struct1* s1 = (struct1*)object; 
    printf("struct1_method_for_algorithm2: %d %d %d\n", s1->a, s1->b, s1->c); 
    } 
    void struct2_method_for_algorithm1(base* object) { 
    struct2* s2 = (struct2*)object; 
    printf("struct2_method_for_algorithm1: %d %d %d %d %d\n", s2->a, s2->b, s2->c, s2->d, s2->e); 
    } 
    void struct2_method_for_algorithm2(base* object) { 
    struct2* s2 = (struct2*)object; 
    printf("struct2_method_for_algorithm2: %d %d %d %d %d\n", s2->a, s2->b, s2->c, s2->d, s2->e); 
    } 

    int main() { 
    { 
     vtable struct1vtable = { 
     &struct1_method_for_algorithm1, 
     &struct1_method_for_algorithm2 
     }; 
     struct1 a[] = { 
     { &struct1vtable, 10, 20, 30 }, 
     { &struct1vtable, 40, 50, 60 }, 
     }; 
     base* p[] = { &a[0], &a[1] }; 
     algorithm_1(p, 2); 
     algorithm_2(p, 2); 
    } 
    { 
     vtable struct2vtable = { 
     &struct2_method_for_algorithm1, 
     &struct2_method_for_algorithm2 
     }; 
     struct2 a[] = { 
     { &struct2vtable, 10, 20, 30, 40, 50 }, 
     { &struct2vtable, 40, 50, 60, 70, 80 }, 
     }; 
     base* p[] = { &a[0], &a[1] }; 
     algorithm_1(p, 2); 
     algorithm_2(p, 2); 
    } 
    return 0; 
    } 
+0

Это было на самом деле одно из решений, которые я думал ... Я просто боюсь, это немного сложно реализовать и поддерживать. – user8469759

+0

Из любопытства есть люди, которые применяют этот подход к программированию на С? – user8469759

+0

@ user8469759 Обычно такой подход используется, когда вам нужно поддерживать сложную иерархию с полиномическим поведением на C. Я не уверен, что такой подход подходит для вас, но я должен сказать, что такое решение более поддается регулированию, чем подходы с объединением и универсальным массив. – AnatolyS

0

Если union это применимо решение для вас

enum struct_types 
{ 
    typ_struct_1, 
    typ_struct_2 
}; 

struct struct_1{ 
int a; 
int b; 
int c; 
int d; 
}; 

struct struct_2{ 
int a; 
int b; 
int e; 
int f; 
int g; 
int h; 
}; 

struct my_struct 
{ 
    uint8_t struct_type; 

    union u_members 
    { 
     struct struct_1 struct_1_typed; 
     struct struct_2 struct_2_typed; 
     int struct_1_raw[sizeof(struct struct_1)/sizeof(int)]; 
     int struct_2_raw[sizeof(struct struct_2)/sizeof(int)]; 
    }members; 
}; 
+0

Вещь в том, что вы делаете «объединение объединено» p = malloc (sizeof (* p)) 'вы будете выделять для' struct_2', даже если вы используете его только для 'struct_1', теряя пространство (без больших сделка за 2x'int', но может быть проблемой). С другой стороны, если вы выберете 'sizeof (struct_1)', вы будете segfault, если вы когда-нибудь сделаете 'p-> struct_2.h'. – mtijanic

+0

@mtijanic Да, точно так же, если вы 'char * test = malloc (4)' и после 'test [10] = 0;'. Я имею в виду, что вы должны «malloc'-ели правильный размер, иначе не определяете поведение. BTW не обязательно использовать 'malloc' с предлагаемым решением. – LPs

+0

Мои проблемы в этом случае - когда мне нужно реализовать некоторые специальные операции для struct_1 или struct_2, есть причина, по которой я трачу свое время на понимание того, как я могу обойти эту проблему. – user8469759

0

Может быть, вы могли бы определить смещение поля, как это:

enum { 
    /* common struct_1 and struct_2 fields */ 
    a, 
    b, 
    numcommon_fields, 
    /* struct_1 fields */ 
    c = numcommon_fields, 
    d, 
    num1_fields, 
    /* struct_2 fields */ 
    e = numcommon_fields, 
    f, 
    g, 
    h, 
    num2_fields 
}; 
0

Пока общие имена полей имеют один и тот же индекс, вы можете пойти так:

enum struct_fields { 
    a = 0, 
    b, c, d, num1_fields, 
    e = 2, f, g, h, num2_fields 
}; 

// if you need distinct names... 
typedef enum struct_fields struct1_fields; 
typedef enum struct_fields struct2_fields; 

, потому что, если это законно, чтобы иметь более одного член перечисления иметь детерминированное значение,

Как только это будет сделано, вы можете спокойно делать такие вещи, как:

for (i=0; i<num2_fields; i++) { 
    structure[i] = i*2; 
} 
printf("%d %d %d %d\n", structure[a], structure[b], structure[c], structure[d]); 
printf("%d %d %d %d %d %d\n", structure[a], structure[b], 
    structure[e], structure[f], structure[g], structure[h]); 

получить как Ожидаемый результат:

0 2 4 6 
0 2 4 6 8 10 

Но никогда не псевдоним этих массивов к исходному структур, потому что это нарушило бы строгое правило сглаживания

0

Как уже упоминалось, union хорошо работает для того, что вы хотите сделать. И он строго соответствует стандарту C.

Per 6.5.2.3 Состав и членов объединения, пункт 6 C Standard:

ТРУДНОСТИ

...

Особым гарантия делается для того, чтобы упростить использование союзов: , если объединение содержит несколько структур, которые имеют общую начальную последовательность (см. ниже) и если объект объединения в настоящее время содержит одну из этих структур, то разрешено для проверки общей исходной части любого из них в любом месте, где видна декларация завершенного типа объединения . Две структуры имеют общую начальную последовательность, если соответствующие члены имеют совместимые типы (и для битовых полей одинаковой ширины) для последовательности из одного или нескольких начальных элементов.

Например, XEvent объединение X Windows, defined in X11/Xlib.h:

/* 
* this union is defined so Xlib can always use the same sized 
* event structure internally, to avoid memory fragmentation. 
*/ 
typedef union _XEvent { 
    int type;  /* must not be changed; first element */ 
    XAnyEvent xany; 
    XKeyEvent xkey; 
    XButtonEvent xbutton; 
    XMotionEvent xmotion; 
    XCrossingEvent xcrossing; 
    XFocusChangeEvent xfocus; 
    XExposeEvent xexpose; 
    XGraphicsExposeEvent xgraphicsexpose; 
    XNoExposeEvent xnoexpose; 
    XVisibilityEvent xvisibility; 
    XCreateWindowEvent xcreatewindow; 
    XDestroyWindowEvent xdestroywindow; 
    XUnmapEvent xunmap; 
    XMapEvent xmap; 
    XMapRequestEvent xmaprequest; 
    XReparentEvent xreparent; 
    XConfigureEvent xconfigure; 
    XGravityEvent xgravity; 
    XResizeRequestEvent xresizerequest; 
    XConfigureRequestEvent xconfigurerequest; 
    XCirculateEvent xcirculate; 
    XCirculateRequestEvent xcirculaterequest; 
    XPropertyEvent xproperty; 
    XSelectionClearEvent xselectionclear; 
    XSelectionRequestEvent xselectionrequest; 
    XSelectionEvent xselection; 
    XColormapEvent xcolormap; 
    XClientMessageEvent xclient; 
    XMappingEvent xmapping; 
    XErrorEvent xerror; 
    XKeymapEvent xkeymap; 
    long pad[24]; 
} XEvent; 

Все различные типы XEvent начинаются с int type, например:

typedef struct { 
    int type; 
    unsigned long serial; /* # of last request processed by server */ 
    Bool send_event; /* true if this came from a SendEvent request */ 
    Display *display; /* Display the event was read from */ 
    Window window; 
    int width, height; 
} XResizeRequestEvent; 

или

typedef struct { 
    int type; 
    unsigned long serial; /* # of last request processed by server */ 
    Bool send_event; /* true if this came from a SendEvent request */ 
    Display *display; /* Display the event was read from */ 
    Window event; 
    Window window; 
    Bool override_redirect; /* boolean, is override set... */ 
} XMapEvent; 

Фактически, общность выходит далеко за пределы поля int type для большинства типов XEvent. Большинство типов событий начинаются со следующих полей: XAnyEvent:

typedef struct { 
    int type; 
    unsigned long serial; /* # of last request processed by server */ 
    Bool send_event; /* true if this came from a SendEvent request */ 
    Display *display;/* Display the event was read from */ 
    Window window; /* window on which event was requested in event mask */ 
} XAnyEvent; 
Смежные вопросы