struct alignment C/C++
Asked Answered
B

2

30

In c/c++ (I am assuming they are the same in this regard), if I have the following:

struct S {
  T a;
  .
  .
  .
} s;

Is the following guaranteed to be true?

(void*)&s == (void*)&s.a;

Or in other words, is there any kind of guarantee that there will be no padding before the first member?

Brusa answered 24/7, 2013 at 21:27 Comment(2)
They aren't the same in this regardMeandrous
@MooingDuck: Well, it depends on what the ... is. For the same struct definition, C++ will treat it the same way as C (C structures always meet the C++ standard-layout requirement).Ibeam
M
43

In C, yes, they're the same address. Simple, and straightforward.


In C++, no, they're not the same address. Base classes can (and I would suspect, do) come before all members, and virtual member functions usually add hidden data to the struct somewhere. Even more confusing, a C++ compiler may also rearrange members at will, unless the class is a standard layout type (though I don't know that any compiler does so)

Finally, if the C++ struct is composed of standard layout types, contains no base classes nor virtual functions and all members have the same visibility, and possibly other limitations I forgot, then it falls back on the C rules, and requires the first member to be at the same address as the object itself.

§ 9.2/7

A standard-layout class is a class that:
— has no non-static data members of type non-standard-layout class (or array of such types) or reference,
— has no virtual functions (10.3) and no virtual base classes (10.1),
— has the same access control (Clause 11) for all non-static data members,
— has no non-standard-layout base classes,
— either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
— has no base classes of the same type as the first non-static data member.

§ 9.2/20

A pointer to a standard-layout struct object, suitably converted using a reinterpret_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. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. —end note ]

Meandrous answered 24/7, 2013 at 21:30 Comment(6)
"standard-layout class" is also known as POD ("plain old data type"), and you can verify it using std::is_pod.Thundershower
@marcin_j: No. POD requires both standard-layout and trivial construction/copy/destruction. A class can have non-defaulted constructors and destructors and other special members and still be standard-layout.Ibeam
thanks for clarification, I see that it is possible to use std::is_standard_layout<T> to verify if such comparison is correct.Thundershower
"Base classes can (and I would suspect, do) come before all members" -- It's undefined where bases are in layout; some compilers (none of the "mainstream" ones) do put them at the end of the class, iirc.Wharve
@SeanMiddleditch: I was aware it was IB, but I have heard that most compilers put nonvirtual base classes before members, and I've heard mixed things about the placement of virtual base classes.Meandrous
@SeanMiddleditch Of course it is, that's why it is a "can" and not a "do".Ev
R
16

Yes, it is.

It is guaranteed there is no padding before the first struct member in C and in C++ (if it is a POD).

C quote:

(C11, 6.7.2.1p15) "There may be unnamed padding within a structure object, but not at its beginning."

C++ quote:

(C++11, 9.2p20) "There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment"

Recitation answered 24/7, 2013 at 21:28 Comment(7)
In C++ it is only guaranteed if it's a POD.Pish
@n.m. added a quote for C++ and a mention for POD. ThanksRecitation
@n.m. If what is a POD? The struct S or the member T?Brusa
The comparison &s == &s.a is illegal, since struct S* and T* are not compatible types. But (void*)&s == (void*)&s.aEbenezer
What if we take the address of each element of a class instance? Can they move freely after that?Tess
@baruch: S (and therefore also T, because a struct is a POD only if all its members are POD).Pish
@huseyintugrulbuyukisik If you mean move at runtime? Then no. The compiler may rearrange them, but the runtime won't. Correctly, it can't because it doesn't know where objects are located.Parclose

© 2022 - 2024 — McMap. All rights reserved.