Are members of a POD-struct or standard layout type guaranteed to be aligned according to their alignment requirements?
Asked Answered
E

2

14

Given a POD-struct (in C++03) or a standard layout type (in C++11), with all members having a fundamental alignment requirement, is it true that every member is guaranteed to be aligned according to its alignment requirement?

In other words, for all members m_k in { m0 ... mn } of standard layout type S,

struct S {
    T0 m0;
    T1 m1;
    ...
    TN mn;
};

is the following expression guaranteed to evaluate to true?

(offsetof(S,m_k) % alignof(decltype(S::m_k))) == 0

Please give answers for both C++03 and C++11 and cite the relevant parts of the standard. Supporting evidence from C standards would also be helpful.


My reading of the C++03 standard (ISO/IEC 14882:2003(E)) is that it is silent regarding the alignment of members within a POD-struct, except for the first member. The relevant paragraphs are:

In the language of the specification, an object is a "region of storage":

1.8 The C + + object model [intro.object]

1.8/1 The constructs in a C + + program create, destroy, refer to, access, and manipulate objects. An object is a region of storage. ...

Objects are allocated according to their alignment requirement:

3.9 Types [basic.types]

3.9/5 Object types have alignment requirements (3.9.1, 3.9.2). The alignment of a complete object type is an implementation-defined integer value representing a number of bytes; an object is allocated at an address that meets the alignment requirements of its object type.

Fundamental types have alignment requirements:

3.9.1 Fundamental types [basic.fundamental]

3.9.1/3 For each of the signed integer types, there exists a corresponding (but different) unsigned integer type: "unsigned char", "unsigned short int", "unsigned int", and "unsigned long int," each of which occupies the same amount of storage and has the same alignment requirements (3.9) as the corresponding signed integer type;...

Padding may occur due to "implementation alignment requirements":

9.2 Class members [class.mem]

9.2/12 Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).

Does the word "allocated" in 9.2/12 have the same meaning as "allocated" in 3.9/5? Most uses of "allocated" in the spec refer to dynamic storage allocation, not struct-internal layout. The use of may in 9.2/12 seems to imply that the alignment requirements of 3.9/5 and 3.9.1/3 might not be strictly required for struct members.

The first member of a POD-struct will be aligned according to the alignment requirement of the struct:

9.2/17 A pointer to a POD-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 POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment. ]

[Emphasis added in all of the above quotes.]

Eec answered 21/9, 2015 at 16:20 Comment(3)
The word "object" in the reference to alignment requirements means "object", not just "most compounded object". (viz. the definition of compound types in which it says "classes containing a sequence of objects of various types".)Ylla
@rici: thanks. I've added the definition of object from the spec: "a region of storage".Eec
Ross: correct. A region of storage. Not an independent region of storage. An object within a compound object is still an object and therefore still subject to alignment requirements. The conditional ("might") in 9.2/17 is simply a recognition that the alignment requirement might or might not require padding; it is not permission to avoid the alignment requirement.Ylla
P
11

Each element of a POD struct is itself an object, and objects can only be allocated in accordance with the alignment requirements for those objects. The alignment requirements may change, though, due to the fact that something is a sub-object of another object ([basic.align]/1, 2:

1 Object types have alignment requirements (3.9.1, 3.9.2) which place restrictions on the addresses at which an object of that type may be allocated. An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type; stricter alignment can be requested using the alignment specifier (7.6.2).

2 A fundamental alignment is represented by an alignment less than or equal to the greatest alignment supported by the implementation in all contexts, which is equal to alignof(std::max_align_t) (18.2). The alignment required for a type might be different when it is used as the type of a complete object and when it is used as the type of a subobject. [Example:

struct B { long double d; };
struct D : virtual B { char c; }

When D is the type of a complete object, it will have a subobject of type B, so it must be aligned appropriately for a long double. If D appears as a subobject of another object that also has B as a virtual base class, the B subobject might be part of a different subobject, reducing the alignment requirements on the D subobject.—end example ] The result of the alignof operator reflects the alignment requirement of the type in the complete-object case.

[emphasis added]

Although the examples refer to a sub-object via inheritance, the normative wording just refers to sub-objects in general, so I believe the same rules apply, so on one hand you can assume that each sub-object is aligned so that it can be accessed. On the other hand, no you can't necessarily assume that will be the same alignment that alignof gives you.

[The reference is from N4296, but I believe the same applies to all recent versions. C++98/03, of course, didn't have alignof at all, but I believe the same basic principle applies--members will be aligned so they can be used, but that alignment requirement isn't necessarily the same as when they're used as independent objects.]

Piperidine answered 21/9, 2015 at 16:40 Comment(16)
@JerryCoffin My question is specifically about POD-structs and standard layout types. So, interesting as it is, I'm not sure how the virtual base class example applies. Do you think there's anything that strengthens the assumptions that I can make in the POD/SLT case?Eec
@Ylla No, it doesn't have to be at least that. The point of subobject alignment requirements is that they could be weaker.Brewington
@Columbo: subobject alignment cannot be less than the fundamental alignment of a fundamental type. But I agree that my assertion needed qualification.Ylla
@Ylla If by "fundamental alignment of a fundamental type" you mean a type's complete object alignment requirement, then no, the subobject requirement can be weaker (as the standard never says otherwise - they are independent requirements). That said, it doesn't matter whether any of the invoked alignment requirements is fundamental or not.Brewington
@RossBencina: Realistically, the assumption you want to make is probably safe for POD/SL cases, but I doubt there's much in the standard to support that.Piperidine
@Colombo: find me an example where the standard allows an int member to not be aligned to alignof(int), then.Ylla
With respect to: "The alignment required for a type might be different when it is used as the type of a complete object and when it is used as the type of a subobject" > What if the type is guaranteed to be a fundamental type? Does that change things?Eec
@Ylla First of all, my name is Columbo. Secondly, I never said that it was possible for int. We were talking about standard layout types, not int specifically.Brewington
@Colomnぼ And here I thought you where part of a Japanese database.Schwarz
@Columbo: Sorry about the typo. I said "alignment of a fundamental type"; not all SL types are fundamental. (3.9.1). I'm pretty sure that 9.2/20 recursively applied requires that an SL type has the same address (and therefore alignment) as some fundamental type, but I'm not going to attempt a formal proof before lunch.Ylla
@Ylla Who said that the alignment requirement of a subobject of fundamental type cannot differ from what alignof tells us? Just because common ABIs don't do that, doesn't imply they couldn't. Also, an object of standard layout type can be defined to have alignment 128 if the implementation supports extended alignment, so your proof cannot work for those.Brewington
@Brewington I do appreciate the extra clarifying detail about where things can go wrong, but please note that the matter in question specifically concerns member sub-objects with "fundamental alignment requirement" (see first paragraph of the question).Eec
@RossBenica And what difference does that make? Why can't I align an int per 1 in structs if its usual alignment is 4?Brewington
@Columbo: It seems I have no legal grounds to disagree. But it seems against the spirit of alignof(int) to allow it to be misaligned in some contexts but not in others.Eec
@RossBencina whence the suggestion that anything will "allow [int] to be misaligned in some contexts"? others have shown that structs can be differently aligned in different scenarios - but not contested your opening quote that their fundamental members' alignments must be preserved. an implementation could choose to 'squeeze' struct SomeStruct { int i; }; into the space after struct OtherStruct { long l; int i; }; if these structs appeared as subobjects together - but in no case is any int or other fundamental becoming misaligned due to any of thisEffortful
@Effortful The bold highlighted portions of this answer imply that the alignment requirement in the sub-object case is unspecified ("might be different"). So far, no one has been able to point to a section of the specification that explicitly precludes misalignment in the sub-object case (all cites so far deal with complete objects). It is a while since I looked, but my conclusion was that the spec contains no explicit exclusion of this possibility. Hence why Columbo said "Why can't I align an int per 1 in structs if its usual alignment is 4?"Eec
B
6

There are two distinct alignment requirements for each type. One corresponds to complete objects, the other one to subobjects. [basic.align]/2:

The alignment required for a type might be different when it is used as the type of a complete object and when it is used as the type of a subobject. [ Example:

struct B { long double d; };
struct D : virtual B { char c; };

When D is the type of a complete object, it will have a subobject of type B, so it must be aligned appropriately for a long double. If D appears as a subobject of another object that also has B as a virtual base class, the B subobject might be part of a different subobject, reducing the alignment requirements on the D subobject. —end example ] The result of the alignof operator reflects the alignment requirement of the type in the complete-object case.

I can't think of any specific example for member subobjects - and there assuredly is none! -, but the above paragraph concedes the possibility that a member subobject has weaker alignment than alignof will yield, which would fail your condition.

Brewington answered 21/9, 2015 at 16:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.