I'm implementing a binary tree in C89, and I'm trying to share common attributes among all node structs through composition. Thus I have the following code:
enum foo_type
{
FOO_TYPE_A,
FOO_TYPE_B
};
struct foo {
enum foo_type type;
};
struct foo_type_a {
struct foo base;
struct foo * ptr;
};
struct foo_type_b {
struct foo base;
char * text;
};
I'm including a member of type struct foo
in all struct definitions as their initial member in order to provide access to the value held by enum foo_type
regardless of struct type. To achieve this I'm expecting that a pointer to a structure object points to its initial member, but I'm not sure if this assumption holds in this case. With C99, the standard states the following (see ISO/IEC 9899:1999 6.7.2.1 §13)
A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.
Although all structs share a common struct foo
object as their initial member, padding comes into play. While struct foo
only has a single member which is as int
size, both struct foo_type_a
and struct foo_type_b
include pointer members, which in some cases increase the alignment and thus adds padding.
So, considering this scenario, does the C programming language (C89 or any subsequent version) ensures that it's safe to access the value of struct foo::type
through a pointer to an object, whether that object is of type struct foo
or includes an object of type struct foo
as its first member, such as struct foo_type_a
or struct foo_type_b
?
As you yourself quote from the C Standard, what you describe is supported by C99 and later versions.
Is appears it was also supported by C89 as the language you quoted was already present in the ANSI-C document from 1988:
3.5.2.1 Structure and union specifiers
...
Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may therefore be unnamed holes within a structure object, but not at its beginning, as necessary to achieve the appropriate alignment.