views:

172

answers:

7

I was wondering:

If I have structure definitions, for example, like this:

struct Base {
  int foo;
};

struct Derived {
  int foo; // int foo is common for both definitions
  char *bar;
};

can I do something like this?

void foobar(void *ptr) {
  ((struct Base *)ptr)->foo = 1;
}

struct Derived s;

foobar(&s);

e. g. cast the void pointer to Base * to access its foo when its type is actually Derived *?

+1  A: 

In particular cases this could work, but in general - no, because of the structure alignment.

You could use different #pragmas to make (actually, attempt to) the alignment identical - and then, yes, that would work.

If you're using microsoft visual studio, you might find this article useful.

HardCoder1986
remove dot at end of link :)
Rin
Figured that out :)
Anon
A: 

The great/bad thing about C is that you can cast just about anything -- the problem is, it might not work. :) However, in your case, it will*, since you have two structs whose first members are both of the same type; see this program for an example. Now, if struct derived had a different type as its first element -- for example, char *bar -- then no, you'd get weird behavior.

* I should qualitfy that with "almost always", I suppose; there're a lot of different C compilers out there, so some may have different behavior. However, I know it'll work in GCC.

mipadi
+1  A: 

That will work in this particular case. The foo field in the first member of both structures and hit has the same type. However this is not true in the general case of fields within a struct (that are not the first member). Items like alignment and packing can make this break in subtle ways.

JaredPar
+4  A: 

This specific case, and similar ones, are guaranteed to work by the C standard: the common initial sequence rule says that if you have two struct types that begin with the same sequence of members, then that initial sequence will be laid out in memory the same way in both structures, and you can cast between them without breaking the aliasing rules, as long as you only try to access the initial sequence.

C99 §6.5.2.3 p5 -- technically the guarantee only applies if all the structures in question are part of the same union, but the compiler pretty much has to assume there is such a union somewhere in your program, so in practice it works without the union. See also §6.2.7 (type compatibility in general).

Zack
Different structures can have different alignment requirements. A union would make sure that the most strict alignment is obeyed. Without a union (this case) you have no such guarantee, making the cast possible UB.
schot
section 6.5.2.3 §8 has an example where it's explicitly shown that the common initial sequence rule only applies if the union definition is in scope; an aggressively optimizing compiler is free to assume that a `struct Base *` and a `struct Derived *` don't alias each other if there's no appropriate union definition
Christoph
These are both theoretical possibilities that do not occur in practice. It is enough of an uphill battle getting all the _other_ type-aliasing violations out of legacy C applications without worrying about structures with a common initial sequence. The alignment issue is even more theoretical; you *could* have an item in `struct Derived` that forced actual `Derived` objects to be more aligned than `struct Base`, but any `Base` object aligned properly for itself will still be well-aligned for all accesses to members of the common initial sequence when treated as a `Derived`.
Zack
+6  A: 

You should do

struct Base {
  int foo;
};

struct Derived {
  struct Base base;
  char *bar;
};

to avoid breaking strict aliasing; it is a common misconception that C allows arbitrary casts of pointer types: although it will work as expected in most implementations, it's non-standard.

This also avoids any alignment incompatibilities due to usage of pragma directives.

Christoph
+1 - the original example is safe, but this is still good practice.
Zack
+1  A: 

As you seem to be aiming at Object Oriented Programming in C I can suggest you to have a look at the following link:

http://www.planetpdf.com/codecuts/pdfs/ooc.pdf

It goes into detail about ways of handling oop principles in ANSI C.

gilligan
Thanks, that seems to be the first resource I'm consulting that is actually useful :)
Anon
It is also called "poor man's OOP".
ruslik
A: 

There is another little thing that might be helpful or related to what you are doing ..

#define SHARED_DATA int id;

typedef union base_t {
    SHARED_DATA;
    window_t win;
    list_t   list;
    button_t button;         
}

typedef struct window_t {
    SHARED_DATA;
    int something;
    void* blah;
}

typedef struct window_t {
    SHARED_DATA;
    int size;
 }

typedef struct button_t {
    SHARED_DATA;
    int clicked;
 }

Now you can put the shared properties into SHARED_DATA and handle the different types via the "superclass" packed into the union.. You could use SHARED_DATA to store just a 'class identifier' or store a pointer.. Either way it turned out handy for generic handling of event types for me at some point. Hope i'm not going too much off-topic with this

gilligan