Question

I'm writing a C program in which I define two types:

typedef struct {

    uint8_t array[32];
    /* struct A's members */
    ...

} A;

typedef struct {

    uint8_t array[32];
    /* struct B's members, different from A's */
    ...

} B;

Now I would like to build a data structure which is capable of managing both types without having to write one for type A and one for type B, assuming that both have a uint8_t [32] as their first member.

I read how to implement a sort of polymorphism in C here and I also read here that the order of struct members is guaranteed to be kept by the compiler as written by the programmer.

I came up with the following idea, what if I define the following structure:

typedef struct {
    uint8_t array[32];
} Element;

and define a data structure which only deals with data that have type Element? Would it be safe to do something like:

void f(Element * e){
    int i;
    for(i = 0; i < 32; i++) do_something(e->array[i]);
}

...

A a;
B b;
...
f(((Element *)&a));
...
f(((Element *)&b));

At a first glance it looks unclean, but I was wondering whether there are any guarantees that it will not break?

Was it helpful?

Solution

If array is always the first in your struct, you can simply access it by casting pointers. There is no need for a struct Element. You data structure can store void pointers.

typedef struct {
    char array[32];
} A;

typedef struct {
    void* elements;
    size_t elementSize;
    size_t num;
} Vector;

char* getArrayPtr(Vector* v, int i) {
    return (char*)(v->elements) + v->elementSize*i;
}

int main()
{
    A* pa = malloc(10*sizeof(A));
    pa[3].array[0] = 's';
    Vector v;
    v.elements = pa;
    v.num = 10;
    v.elementSize = sizeof(A);
    printf("%s\n", getArrayPtr(&v, 3));
}

OTHER TIPS

but why not have a function that works with the array directly void f(uint8_t array[32]){ int i; for(i = 0; i < 32; i++) do_something(array[i]); }

and call it like this f(a.array) f(b.array)

polymorphism makes sense when you want to kepp a and b in a container of some sorts and you want to iterate over them but you dont want to care that they are different types.

This should work fine if you, you know, don't make any mistakes. A pointer to the A struct can be cast to a pointer to the element struct, and so long as they have a common prefix, access to the common members will work just fine.

A pointer to the A struct, which is then cast to a pointer to the element struct can also be cast back to a pointer to the A struct without any problems. If element struct was not originally an A struct, then casting the pointer back to A will be undefined behavior. And this you will need to manage manually.

One gotcha (that I've run into) is, gcc will also allow you to cast the struct back and forth (not just pointer to struct) and this is not supported by the C standard. It will appear to work fine until your (my) friend tries to port the code to a different compiler (suncc) at which point it will break. Or rather, it won't even compile.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top