3

We have following structs:

struct parent {
    char *name;
};

struct child {
    struct parent parent;
    int other_child_specific_data;
};

And also we have function which works with struct parent:

void print_parent_name(struct parent *p)
{
    printf("%s\n", p->name);
}

Question: can I be sure, that calling that function like this:

struct child c;
c.parent.name = "Child #1";

print_parent_name(&c);

will be always the same as

print_parent_name(&c + offsetof(struct child, parent));

?

In other words, the question is: will be offsetof(struct child, parent) always equal to zero if struct parent parent is placed as first definition at struct child?

May be somebody can give a ref to C standard? And are there such hardware or software configurations that make offsetof(struct child, parent) in such structs not equal to zero?

zdo
  • 33
  • 3

2 Answers2

5

Yes, the offset of the first element of a struct in C (or C++, subject to certain C-like conditions) is guaranteed to be zero.

For reference, see the C99 standard quoted in https://stackoverflow.com/a/10958596/4323:

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

Community
  • 1
  • 1
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
3

Yes, you can be sure. Structs are always setup in the order in which their members are defined, and alignment cannot make a nonzero offset out of a zero offset.

However, your line

print_parent_name(&c + offsetof(struct child, parent));

won't do what you want, because &c is the pointer to your struct, and you invoke pointer arithmetic, multiplying the offset with the size of the struct. Of course, this is without effect if the offset is zero anyway, but if I were you, I would use this:

print_parent_name(&c.parent);

This has the nice effect of avoiding pointer casts.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106