I've been poring over the draft standard and can't seem to find what I'm looking for.
If I have a standard-layout type
struct T {
unsigned handle;
};
Then I know that reinterpret_cast<unsigned*>(&t) == &t.handle for some T t;
The goal is to create some vector<T> v and pass &v[0] to a C function that expects a pointer to an array of unsigned integers.
So, does the standard define sizeof(T) == sizeof(unsigned) and does that imply that an array of T would have the same layout as an array of unsigned?
While this question addresses a very similar topic, I'm asking about the specific case where both the data member and the class are standard layout, and the data member is a fundamental type.
I've read some paragraphs that seem to hint that maybe it might be true, but nothing that hits the nail on the head. For example:
§ 9.2.17
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
This isn't quite what I'm looking for, I don't think.
You essentially are asking, given:
struct T {
U handle;
};
whether it's guaranteed that sizeof(T) == sizeof(U). No, it is not.
Section 9.2/17 of the ISO C++03 standard says:
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.
Suppose you have an array of struct T. The vice versa part means that the address of any of the T::handle members must also be a valid address of a struct T. Now, suppose that these members are of type char and that your claim is true. This would mean that struct T would be allowed to have an unaligned address, which seems rather unlikely. The standard usually tries to not tie the hands of implementations in such a way. For your claim to be true, the standard would have to require that struct T be allowed to have unaligned addresses. And it would have to be allowed for all structures, because struct T could be a forward-declared, opaque type.
Furthermore, section 9.2/17 goes on to state:
[Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment.]
Which, taken a different way, means that there is no guarantee that there will never be padding.
I am used to Borland environments and for them:
T is a struct in your case so sizeof(T) is size of struct
that depends on #pragma pack and align setting of your compiler
so sometimes it can be greater than sizeof(unsigned) !!!
for the same reason if you have 4Byte struct (uint32) and 16Byte allign
struct T { uint32 u; };
then T a[100] is not the same as uint32 a[100];
because T is uint32 + 12 Byte empty space !!!
RETRACTION: The argument is erroneous. The proof of Lemma 2 relies on a hidden premise that the alignment of an aggregate type is determined strictly by the alignments of its member types. As Dyp points out in the commentary, that premise is not supported by the standard. It is therefore admissible for struct { Foo f } to have a more strict alignment requirement that Foo.
I'll play devil's advocate here, since no one else seems to be willing. I will argue that standard C++ (I'll refer to N3797 herein) guarantees that sizeof(T) == sizeof(U) when T is a standard layout class (9/7) with default alignment having a single default-aligned non-static data member U, e.g,
struct T { // or class, or union
U u;
};
It's well-established that:
sizeof(T) >= sizeof(U)
offsetof(T, u) == 0 (9.2/19)
U must be a standard layout type for T to be a standard layout class
u has a representation consisting of exactly sizeof(U) contiguous bytes of memory (1.8/5)
Together these facts imply that the first sizeof(U) bytes of the representation of T are occupied by the representation of u. If sizeof(T) > sizeof(U), the excess bytes must then be tail padding: unused padding bytes inserted after the representation of u in T.
The argument is, in short:
The standard details the circumstances in which an implementation may add padding to a standard-layout class,
None of those cirumstances applies in this particular instance, and hence
A conforming implementation may not add padding.
Potential Sources of Padding
Under what circumstances does the standard allow an implementation to add such padding to the representation of a standard layout class? When it's necessary for alignment: per 3.11/1, "An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated." There are two mentions of adding padding, both for alignment reasons:
5.3.3 Sizeof [expr.sizeof]/2 states "When applied to a reference or a reference type, the result is the size of the referenced type. When applied
to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array. The size of a most derived class shall be greater than zero (1.8). The result of applying sizeof to a base class subobject is the size of the base class type.77 When applied to an array, the result is the total number of bytes in the array. This implies that the size of an array of n elements is n times the size of an element."
9.2 Class members [class.mem]/13 states "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)."
(Notably the C++ standard does not contain a blanket statement allowing implementations to insert padding in structures as in the C standards, e.g., N1570 (C11-ish) §6.7.2.1/15 "There may be unnamed padding within a structure object, but not at its beginning." and /17 "There may be unnamed padding at the end of a structure or union.")
Clearly the text of 9.2 doesn't apply to our problem, since (a) T has only one member and thus no "adjacent members", and (b) T is standard layout and hence has no virtual functions or virtual base classes (per 9/7). Demonstrating that 5.3.3/2 doesn't allow padding in our problem is more challenging.
Some Prerequisites
Lemma 1: For any type W with default alignment, alignof(W) divides sizeof(W): By 5.3.3/2, the size of an array of n elements of type W is exactly n times sizeof(W) (i.e., there is no "external" padding between array elements). The addresses of consecutive array elements are then sizeof(W) bytes apart. By the definition of alignment, it must then be that alignof(W) divides sizeof(W).
Lemma 2: The alignment alignof(W) of a default-aligned standard layout class W with only default-aligned data members is the least common multiple LCM(W) of the alignments of the data members (or 1 if there are none): Given an address at which an object of W can be allocated, the address LCM(W) bytes away must also be appropriately aligned: the difference between the addresses of member subobjects would also be LCM(W) bytes, and the alignment of each such member subobject divides LCM(W). Per the definition of alignment in 3.11/1, we have that alignof(W) divides LCM(W). Any whole number of bytes n < LCM(W) must not be divisible by the alignment of some member v of W, so an address that is only n bytes away from an address at which an object of W can be allocated is consequently not appropriately aligned for an object of W, i.e., alignof(W) >= LCM(W). Given that alignof(W) divides LCM(W) and alignof(W) >= LCM(W), we have alignof(W) == LCM(W).
Conclusion
Application of this lemma to the original problem has the immediate consequence that alignof(T) == alignof(U). So how much padding might be "required for placing objects of that type in an array"? None. Since alignof(T) == alignof(U) by the second lemma, and alignof(U) divides sizeof(U) by the first, it must be that alignof(T) divides sizeof(U) so zero bytes of padding are required to place objects of type T in an array.
Since all possible sources of padding bytes have been eliminated, an implementation may not add padding to T and we have sizeof(T) == sizeof(U) as required.
Related
The question is more of theory-based than practical implementation.
What I would like to know is, in the code:
struct temp {
int num;
struct temp *next;
};
In the structure made above, how does the compiler decide how much of space should be allocated in memory when we instantiate it?
If I try to dry-run the code, the size of an integer would be 2 or 4 bytes, after that, if I try to find the size of the pointer to the structure itself, I enter a structure containing another integer and a pointer to itself.
By this logic, the compiler would enter an infinite loop when deciding to allocate space to an element of this structure, how then is the space decided?
P.S. I did try to find out the size of this structure myself (using the sizeof() operator, it turned out to be 16 bytes (the size of the integer being 4 bytes)... I'm interested in knowing how did it determine this figure of 16 bytes as the space required!
A structure containing a pointer to itself is not a problem.
A pointer has a fixed size, so it doesn't matter how big the size of the structure it points to is. On most systems you're likely to come across, a pointer will be either 4 bytes or 8 bytes in size.
For the struct you've given, the int field will probably use 4 bytes and the struct temp * field will probably use 8 bytes. This means the struct will be at least 12 bytes in size, probably 16 due to padding for proper alignment.
If on the other hand you had something like this:
struct temp {
int num;
struct temp next;
};
This would not be legal because the struct contains a copy of itself, which would in turn contain a copy of itself, and so on.
In the structure made above, how does the compiler decide how much of space should be allocated in memory when we instantiate it?
Pointer types take up a fixed size, which is not dependent on the pointed-to type (IOW, the size and representation of struct temp * is not in any way dependent on the size or representation of struct temp). Furthermore, all pointer to struct types have the same size:
6.2.5 Types
...
28 A pointer to void shall have the same representation and alignment requirements as a
pointer to a character type.48) Similarly, pointers to qualified or unqualified versions of
compatible types shall have the same representation and alignment requirements. All
pointers to structure types shall have the same representation and alignment requirements
as each other. All pointers to union types shall have the same representation and
alignment requirements as each other. Pointers to other types need not have the same
representation or alignment requirements.
C 2011 online draft
On platforms like x86, all pointer types have the same size and representation, but the standard has to take oddball architectures into account.
It's no different than if you had a pointer to int or pointer to void as a member. The only thing that makes it look weird is that you're creating a self-referential pointer, which is allowed:
6.7.2.1 Structure and union specifiers
...
3 A structure or union shall not contain a member with incomplete or function type (hence,
a structure shall not contain an instance of itself, but may contain a pointer to an instance
of itself), except that the last member of a structure with more than one named member
may have incomplete array type; such a structure (and any union containing, possibly
recursively, a member that is such a structure) shall not be a member of a structure or an
element of an array.
ibid.
Even though the struct type itself is not complete until the closing } of the definition, any pointer to it is complete (that is, its size is known).
The size of the pointed-to type matters for pointer arithmetic (i.e., the address value resulting from p + 1 will depend on the size of the thing p points to). However, it doesn't matter for storing the pointer itself.
Consider the following struct definition:
#define SIZE ... // it's a positive multiple of sizeof(Foo*)
struct Foo {
Foo* ptr;
char padding[SIZE - sizeof(Foo*)];
};
Given that SIZE is a positive multiple of the pointer size (sizeof(Foo*)), is it guaranteed by the standard that sizeof(Foo) == SIZE?
If it is not guaranteed, as a practical matter, are there any platforms in common use that provide a counter-example (where the equality doesn't hold)?
Yes, I'm aware of alignas...
There is no guarantee about padding.
C++ Standard (working draft n4741) 6.7(4) Types
4 The object representation of an object of type T is the sequence of N
unsigned char objects taken up by the object of type T, where N equals
sizeof(T). The value representation of an object is the set of bits that
hold the value of type T. Bits in the object representation that are not
part of the value representation are padding bits. For trivially copyable
types, the value representation is a set of bits in the object
representation that determines a value, which is one discrete element of
an implementation-defined set of values. (41)
(41) The intent is that the memory model of C++ is compatible with that
of ISO/IEC 9899 Programming Language C.
C++ Standard (working draft n4741) 8.5.2.3(2) Sizeof
When applied to a reference or a reference type, the result is the size
of the referenced type. When applied to a class, the result is the
number of bytes in an object of that class including any padding required
for placing objects of that type in an array. The result of applying
sizeof to a potentially-overlapping subobject is the size of the type,
not the size of the subobject.78 When applied to an array, the result is
the total number of bytes in the array. This implies that the size of an
array of n elements is n times the size of an element.
I can point to no example, off-hand, where it would not hold, but based on the standard's memory model compatibility with "ISO/IEC 9899 Programming Language C", there can be no guarantees given regarding padding -- it is implementation defined.
Suppose I have a POD type like this:
struct A {
char a;
int b;
};
On my system, sizeof(A) == 8, even though sizeof(char) == 1 and sizeof(b) == 4. This means that the data structure has 3 unused bytes.
Now suppose we do
A x = ...;
A y =x;
Question:
Is it guaranteed that all 8 bytes of x and y will be identical, even those 3 unused ones?
Equivalently, if I transfer the underlying bytes of some A objects to another program that does not understand their meaning or structure, and treats them as an array of 8 bytes, can that other program safely compare two As for equality?
Note: In an experiment with gcc 7, it appears that those bytes do get copied. I would like to know if this is guaranteed.
The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move
of its bases and members.
12.8/15 [class.copy] in N4141
The bit pattern in the padding bytes is thus allowed to differ.
It's not authoritative, but cppreference's entry for std::memcmp suggests that the padding bytes may differ:
memcmp() between two objects of type struct{char c; int n;} will compare the padding bytes whose values may differ when the values of c and n are the same
given that you asked about a POD type ( hence including unions ) it's worth mentioning that according to [class.copy]
The implicitly-defined copy/move constructor for a union X copies the object representation (6.9) of X
that for trivially copyable types should include padding bits as well.
So, it could be just a matter of replacing A with
union A{ struct {
char a;
int b;
}; };
(actually, the above uses a non standard anonymous struct, but you get the point ... )
Answering your second question:
Equivalently, if I transfer the underlying bytes of some A objects to another program that does not understand their meaning or structure, and treats them as an array of 8 bytes, can that other program safely compare two As for equality?
As an object of your type may contain padding bytes, another program generally can not compare two such objects for equality:
Knowing which bits of the bytes that make out the object semantically is the key for defining its value representation. However, in this scenario, the target program only knows the object representation, i.e. the sequence of bytes representing such an object in memory, including padding bytes. A function like memcmp can only compare such objects whose value representation is identical to its object representation in a meaningful way. If you use it to compare objects value-wise even though they have padding, it may fail to give the right results as it cannot tell which bits in the object representation are irrelevant for the value representations of two objects to be equal.
See http://en.cppreference.com/w/cpp/language/object
Sort of related to my previous question:
Do elements of arrays count as a common initial sequence?
struct arr4 { int arr[4]; };
struct arr2 { int arr[2]; };
union U
{
arr4 _arr4;
arr2 _arr2;
};
U u;
u._arr4.arr[0] = 0; //write to active
u._arr2.arr[0]; //read from inactive
According to this cppreference page:
In a standard-layout union with an active member of non-union class type T1, it is permitted to read a non-static data member m of another union member of non-union class type T2 provided m is part of the common initial sequence of T1 and T2....
Would this be legal, or would it also be illegal type punning?
C++11 says (9.2):
If a standard-layout union contains two or more standard-layout structs that share a common initial sequence,
and if the standard-layout union object currently contains one of these standard-layout structs, it is permitted
to inspect the common initial part of any of them. Two standard-layout structs share a common initial
sequence if corresponding members have layout-compatible types and either neither member is a bit-field or
both are bit-fields with the same width for a sequence of one or more initial members.
As to whether arrays of different size form a valid common initial sequence, 3.9 says:
If two types T1 and T2 are the same type, then T1 and T2 are layout-compatible types
These arrays are not the same type, so this doesn't apply. There is no special further exception for arrays, so the arrays may not be layout-compatible and do not form a common initial sequence.
In practice, though, I know of a compiler (GCC) which:
ignores the "common initial sequence" rule, and
allows type punning anyway, but only when accesses are "via the union type" (as in your example), in which case the "common initial sequence" rule is obeyed indirectly (because a "common initial sequence" implies a common initial layout on the architectures the compiler supports).
I suspect many other compilers take a similar approach. In your example, where you type-pun via the union object, such compilers will give you the expected result - reading from the inactive member should give you value written via the inactive member.
The C Standard would allow an implementation to vary the placement of an array object within a structure based upon the number of elements. Among other things, there may be some circumstances where it may be useful to word-align a byte array which would occupy exactly one word, but not to word-align arrays of other sizes. For example, on a system with 8-bit char and 32-bit words, processing a structure such as:
struct foo {
char header;
char dat[4];
};
in a manner that word-aligns dat may allow an access to dat[i] to be processed by loading a word and shifting it right by a 0, 8, 16, or 24 bits, but such advantages might not be applicable had the structure instead been:
struct foo {
char header;
char dat[5];
};
The Standard was clearly not intended to forbid implementations from laying out structures in such ways, on platforms where doing so would be useful. On the other hand, when the Standard was written, compilers which would place arrays within a structure at offsets that were unaffected by the arrays' sizes would unanimously behave as though array elements that were present in two structures were part of the same Common Initial Sequence, and nothing in the published Rationale for the Standard suggests any intention to discourage such implementations from continuing to behave in such fashion. Code which relied upon such treatment would have been "non-portable", but correct on all implementations which followed common struct layout practices.
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.]
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.]
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.