Search code examples
cmemory-alignmentc89packing

struct packing: how to add struct members at the beginning?


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?


Solution

  • 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.