문제

I was reading somewhere about how some object oriented features can be implemented in C, and it has proven fairly useful. In specific, I have been toying with the idea of inheritance. Here is an example:

typedef struct Circle{
     int rad, x, y;
     //Other things...
} Circle;

typedef struct Entity{
    Circle body;
    //Entity-specific items...
} Entity;

This is simple, but it allows for something sneaky. A pointer to an Entity is ALSO a pointer to a Circle because the first element of an Entity is always a Circle. With this idea, we can construct the following function:

int checkCircleCollision(Circle* one, Circle* two);

And call it as such:

Entity* myentity = createEntity(/* Things specific to my entity */);
Entity* myotherentity = createEntity(/* Different things */);
//Did they collide?
if (checkCircleCollision(myentity, myotherentity)){
    /* ... */
}

This is wonderful, but I ran into a problem. What if I wanted some of my Entities to be rectangles, too? I have a solution, but I'd like confirmation that it will always work, no matter the compiler. My knowledge on unions is very limited.

//Circle defined as above...
typedef struct Rectangle{
    int x, y, w, h;
    //Other things...
} Rectangle;

int checkRectangleCollision(Rectangle* one, Rectangle* two);
int checkRectangleCircleCollision(Rectangle* rect, Circle* circ);

typedef struct Entity{
     union{
         Rectangle rect;
         Circle circ;
     } shape;
     int type;
     //Entity things...
}

Is it now completely safe to assume that the first element of an Entity is either a Rectangle or a Circle, depending on its initialization? Furthermore, could it be used in any of the three functions described above? Bonus points for relevant quotes from the standard. To be perfectly clear, I'd like to do this:

Entity* rectentity = createEntity(RECTANGLE, /* width/height/etc */);
Entity* circentity = createEntity(CIRCLE, /* rad/x/y/etc */ );
if (checkRectangleCircleCollision(rectentity, circentity)){
     /* ... */
}
도움이 되었습니까?

해결책

Is it now completely safe to assume that the first element of an Entity is either a Rectangle or a Circle, depending on its initialization?

Yes.

Bonus points for relevant quotes from the standard.

  • "A union type describes an overlapping nonempty set of member objects, each of which has an optionally specified name and possibly distinct type." (C99, 6.2.5.20)

  • "A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa." (6.7.2.1.14)

다른 팁

A union, regardless of its active field, is always aligned on the same memory address. For example, consider the following:

#include <stdio.h>

int main(void)
{  
    union typeUnion
    {
        int i;
        float f; 
    } u;

    u.i = 5;    
    printf("%-4d (%p)\n", u.i, &u.i);

    u.f = 3.14;
    printf("%.2f (%p)", u.f, &u.f);

    return 0;
}

Output on my machine:

5    (0x22aac0) 
3.14 (0x22aac0)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top