10

If I have a struct like this:

struct S {
    ANY_TYPE a;
    ANY_TYPE b;
    ANY_TYPE c;
} s;

Can I safely assume that the following assumptions will always be true on all platforms?

((char *)&s.a) < ((char *)&s.c)
((char *)&s.a + sizeof(s.a) + sizeof(s.b)) <= ((char *)&s.c)

In C++ too?

airman
  • 564
  • 1
  • 4
  • 16

6 Answers6

7

Yes, in C at least. The compiler is free to insert padding after any structure member but it must not reorder the members.

It must also not insert padding before the first member.

From C99, 6.7.2.1:

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

15/ There may be unnamed padding at the end of a structure or union.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Re *It must also not insert padding before the first member.*: That would make most compilers are non-compliant. Adding a vtable before the first member is a very common approach to implementing polymorphism. – David Hammen Oct 17 '11 at 12:46
  • 8
    @DavidHammen First of all, vtables are an implementation detail of C++, not C. Secondly, the no-padding-before-first-member requirement is for POD (Plain Old Data) only. Classes with vtables are not POD, and thus are allowed to have a.o. a vtable pointer before the first data member. – Sjoerd Oct 17 '11 at 13:12
5

This is true for a struct, but changes in C++ as soon as you introduce access specifiers. The compiler is allowed to reorder whole blocks delimited by access specifiers.

pmr
  • 58,701
  • 10
  • 113
  • 156
  • Is that really true? The standard says, that member variables are initialized in the order they are listed in the class. I'm assuming that their relative ordering can't be changed thanks to that. – Xeo Oct 17 '11 at 13:37
  • 2
    @Xeo See (for example) here http://stackoverflow.com/questions/4883655/access-specifier-in-c/4883764#4883764 Unfortunately this answer has no standard quotes. I'll try to provide some. Regarding initialization: Initialization is independent from memory ordering. – pmr Oct 17 '11 at 13:40
2

This changes in C++20 (at least the current draft): if you annotate a, b, and c with [[no_unique_address]] and they happen to be empty structures it's possible that they will all have the same address.

In fact it's more complex - if any two are empty and annotated with that then all 3 can share an address.

Phil Willoughby
  • 1,649
  • 12
  • 16
  • 2
    C++20 hasn't been formalized yet, correct? If so, it may change at any time (however, it's more than likely that it won't). – S.S. Anne Jan 11 '20 at 01:59
1

In C++ you can be certain that these assumptions will hold. In struct like this, the compiler is not allowed to change the order of the members.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
0

Yes, by default C++ compilers aren't allowed to move around elements in a struct which makes both statements trivially true.

orlp
  • 112,504
  • 36
  • 218
  • 315
0
  1. Yes (as long as sizeof(ANY_TYPE) is not 0. Some compilers allow it, which is non-standard -- see Can sizeof return 0 (zero)). You'd be safe with <= or just assume a standard compiler.

  2. Yes

And in C++ too.

Pointer comparison only makes sense inside of arrays and structs/classes, not generally.

Community
  • 1
  • 1
Lou Franco
  • 87,846
  • 14
  • 132
  • 192