1

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?

RAM
  • 2,257
  • 2
  • 19
  • 41
  • 2
    `struct foo` is *always* the same, regardless of whether it's in another struct or on its own. Other struct members cannot make two instance of `struct foo` have different layout in memory – UnholySheep Apr 07 '19 at 15:09
  • @n.m.: There is no need for more code. It is clear they want to know whether C 1989 guarantees that converted a pointer to a structure to a pointer to the type of its first member yields a pointer to its first member. – Eric Postpischil Apr 07 '19 at 15:19
  • 2
    I have to ask, why are you developing new code in 1989 C? – Eric Postpischil Apr 07 '19 at 15:20
  • 1
    Yes it does. The cited guarantee, along with the guarantee that all `pointer-to-struct` types shall have the same representation, is the basis for *conformant* type aliasing. See [What is the strict aliasing rule?](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) – Mark Benningfield Apr 07 '19 at 15:35
  • @UnholySheep my concern is that the C standard also states the caveat that the objects need to be "suitably converted", and I'm not sure if simple casts between pointer types represent a suitable conversion. For example, if by any chance the alignment is bumped from 4 to 8 and endianness magic moves the significant bits around then naive casts might cause problems. – RAM Apr 07 '19 at 15:45
  • @EricPostpischil I'm targeting C89 because last time I've checked (admittedly it was a while ago) full compliance with C99 and later is sadly not widespread among the established C compilers. – RAM Apr 07 '19 at 16:13

1 Answers1

1

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.

Community
  • 1
  • 1
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • But isn't that condition dependent on the pointer being "suitably cast"? If all it took was a simple cast between pointers to structs then I imagine it wouldn't be necessary to specifying the importance of casting objects correctly. – RAM Apr 07 '19 at 15:56
  • 2
    @RAM: “Suitably cast” just means cast to the correct type. If there had been anything more onerous to the conversion requirements, it would have said something. – Eric Postpischil Apr 07 '19 at 16:23
  • @RAM: In the language the Standard *was written to describe*, given `union STOOGE { MOE moe; LARRY larry; CURLY curly;} *p;`, `(MOE*)p` will be equivalent to `p->moe`; both will yield a pointer that can inspect any members of `MOE` that are part of a Common Initial Sequence shared with whatever object is in `*p`. Under the interpretation of the Standard used by gcc and clang, `(MOE*)p` and `p->moe` are still equivalent, but they *both* yield pointers that must either be converted to character pointers before use, or used with functions like `memcpy `which will treat them as char pointers. – supercat Apr 11 '19 at 19:33