22
votes

Are these 2 structs layout-compatible?

struct One {
    float x, y, z;
};

struct Two {
    float c[3];
};

Both contains 3 floats, so in a way, this description can be considered true (from N3797):

16 Two standard-layout struct (Clause 9) types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout-compatible types (3.9).

N4659 has a different text:

The common initial sequence of two standard-layout struct (Clause 12) types is the longest sequence of non-static data members and bit-fields in declaration order, starting with the first such entity in each of the structs, such that corresponding entities have layout-compatible types and either neither entity is a bit-field or both are bit-fields with the same width.

Two standard-layout struct (Clause 12) types are layout-compatible classes if their common initial sequence comprises all members and bit-fields of both classes (6.9).

If the answer is no, they are not layout-compatible, then: was it the intention of the committee? Maybe they do want One and Two to be layout-compatible (maybe a committee member reads this, and can clarify).


Bonus question: is it guaranteed, that sizeof(One)==sizeof(Two)?

2
They may each contain 3 floats but the first one has 3 members and the second one only has one. That said std::complex is allowed to do this so I'm not sureNathanOliver
the size would be the sameRyan
Thinking about alignment. ..if it's greater than 4 bytes then no. But you can force it (in a not portable way). As-is compiler is free to do what's best (according to its optimization target and architecture restrictions)Adriano Repetti
@NathanOliver -- std::complex is part of the standard library, and standard library implementors have to make it work. That can involve non-portable and non-standard techniques that ordinary programmers should not have to deal with.Pete Becker
@PeteBecker Good point.NathanOliver

2 Answers

13
votes

Well, no:

[...] if they have the same number of non-static data members [...]

One has three members: x, y, and z. Two has one member: c. They don't have the same number of non-static data members, therefore they aren't layout compatible.


The new wording is different but you end up at the same place. [basic.types] defines layout-compatible as:

Two types cv1 T1 and cv2 T2 are layout-compatible types if T1 and T2 are the same type, layout-compatible enumerations, or layout-compatible standard-layout class types.

[class.mem] defines layout-compatible classes are:

Two standard-layout struct types are layout-compatible classes if their common initial sequence comprises all members and bit-fields of both classes ([basic.types]).

Where the common initial sequence is:

The common initial sequence of two standard-layout struct types is the longest sequence of non-static data members and bit-fields in declaration order, starting with the first such entity in each of the structs, such that corresponding entities have layout-compatible types and either neither entity is a bit-field or both are bit-fields with the same width.

Here, the first member of One (float x) is not layout-compatible with the first member of Two (float c[3]), so the common initial sequence is empty.

3
votes

The compiler is allowed to add padding between members in a class or struct.

Array elements are in contiguous locations.

They may not be layout compatible depending on how the compiler organizes the members in the struct.