12

Possible Duplicate:
Size of struct with a single element

Given any type A and the following struct:

struct S
{
    A a;
};

Are there any cases where sizeof(S) is greater than sizeof(A)?

For example, can sizeof(std::array<T, n>) be greater than sizeof(T[n])?

Community
  • 1
  • 1
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • Does `std::array` create an array of a wrapped `T`? I wasn't aware of that. – Motti Sep 01 '11 at 11:05
  • @Motti: `std::array` has a single data member `T elems[N]`. – R. Martinho Fernandes Sep 01 '11 at 11:07
  • Wouldn't `sizeof(std::array)` _always_ be greater than `sizeof(T[n])` unless the array length was 1? – Seth Carnegie Sep 01 '11 at 11:10
  • @Seth: why should it be greater? – R. Martinho Fernandes Sep 01 '11 at 11:11
  • @Martinho my point exactly, the question makes an invalid assumption. – Motti Sep 01 '11 at 11:11
  • 3
    For clarity: are you asking whether it's permitted by the standard, or whether anyone is aware of an implementation that actually does it? Or whether anyone can think of a good reason that an implementation might do it? – Steve Jessop Sep 01 '11 at 11:12
  • @Motti: the question doesn't contain an invalid assumption. Type `A` in the struct is "any type". Take it to be `T[n]`, then `std::array` is an example of just such a struct (well, it also has some member functions that `S` doesn't have, but that's not what you said, you said that in order to be an example it would have to contain an array of wrapped `T`. It doesn't need that). – Steve Jessop Sep 01 '11 at 11:13
  • @r. Martinho because the size of an array is bigger than any of its elements unless it only has one element. – Seth Carnegie Sep 01 '11 at 11:14
  • @Steve I searched the standard for the word "padding" and it didn't say anything about this that I saw. – Seth Carnegie Sep 01 '11 at 11:14
  • 2
    @Steve: I'm only interested in what the standard says about this matter. – fredoverflow Sep 01 '11 at 11:14
  • @Steve: This question is partly inspired by [this other question](http://stackoverflow.com/questions/7265173/is-this-nested-array-using-stack-or-heap-memory) in which the OP asks whether a vector of `std::array`s is contiguous. Not sure what's meant by "contiguous", but the strongest possible case would be that you can flatten out multi-dimensional indexes. – Kerrek SB Sep 01 '11 at 11:16
  • @Seth: I don't follow your reasoning. Just to give an example, `sizeof(int[10])` is 40 on my platform, and so is `sizeof(std::array)`. – fredoverflow Sep 01 '11 at 11:16
  • @Seth: but no one is comparing the size of an array with the size of one of its elements. It's comparing the size of a raw array with a wrapped array. – R. Martinho Fernandes Sep 01 '11 at 11:16
  • @R. oh ha, I thought `T[n]` was an index, not an array declaration. Sorry, nevermind then. – Seth Carnegie Sep 01 '11 at 11:18
  • @Seth: Don't worry, everyone gets bitten by the C declarator syntax time and again ;) – fredoverflow Sep 01 '11 at 11:19
  • I'm pretty sure it's allowed, but that there's no compelling reason to do it. Difficult to find all the standardese to back that up though. You could consider an implementation in which `short` is 2 bytes 2-aligned, and `short*` is one bit smaller in range (although not storage) than `void*` and `char*`. Meanwhile, all types bigger than `short` are 4-aligned, and pointers-to-struct are 2 bits smaller than `void*` and `char*`. Therefore, all structs would have to be 4-aligned even if they only contain a `short` or a `char`. I can't prove this implementation is permissible, though. – Steve Jessop Sep 01 '11 at 11:25
  • ... and it would only be worth bothering with on some funny architecture that had 2-bits-bigger and 2-bits-smaller pointer registers and/or addressing modes so that there's a purpose to not just making all object pointers the same. – Steve Jessop Sep 01 '11 at 11:27

6 Answers6

5

Being able to use A inside of S means that the compiler already has knowledge of the structure of A and has already added padding bytes to it. I see no reason for it to add further padding to S, as it already is aligned.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • At the time the compiler knows about the size of A it does not know what it will be further packaged with and so will not pad A until it must, as when it goes into S. – Tavison Sep 01 '11 at 11:10
  • 5
    The compiler will add padding to A when it first encounters its declaration, not later... for example, struct A{char x, int y}; will already be padded. – Luchian Grigore Sep 01 '11 at 11:13
3

While the struct can be padded, on all systems I know, the compiler will pad so that the alignment of the structure is the same as the largest alignment of its members. It does this so that an array of the structure will always be correctly aligned.

So:

struct S 
{
   char a;
} // Size 1, no padding

struct S2 
{
   unsigned int a;
   char b;
} // Size 8, 3 bytes padding (assuming 32 bit integer)

Edit: Note, that compilers can also add internal padding, to keep the alignment of the data correct.

The C/C++ standard doesn't specify any of these detail. What you want is the C ABI (application binary interface) for the system you're running on, which should specify default layout for structs (compilers can choose to override this if they see fit, see also #pragma pack). For an example, look at the X86_64 ABI page 13, which states:

Aggregates and Unions Structures and unions assume the alignment of their most strictly aligned compo- nent. Each member is assigned to the lowest available offset with the appropriate alignment. The size of any object is always a multiple of the object‘s alignment. An array uses the same alignment as its elements, except that a local or global array variable of length at least 16 bytes or a C99 variable-length array variable always has alignment of at least 16 bytes. Structure and union objects can require padding to meet size and alignment constraints. The contents of any padding is undefined.

Dave S
  • 20,507
  • 3
  • 48
  • 68
  • 1
    This question is not about structs with multiple data members. – fredoverflow Sep 01 '11 at 11:27
  • Indeed. I thought also that the fields *may* appear in memory in any order; the compiler is free to order the fields in whatever order it likes and ignore the order you declared them in. I wouldn't expect it to be very common. – Nicholas Wilson Sep 01 '11 at 11:28
  • @Nicholas: data members of POD structs are guaranteed to appear in memory in the order they're declared. IIRC, for non-POD the rule is that in between two access specifiers, data members appear in order, although that might just be public members. – Steve Jessop Sep 01 '11 at 11:34
  • 3
    @Fred: Except a struct with 1 member follows the same rules a struct with multiple. Specially, if there is only 1 member, the alignment of the struct and size must match, and therefore, there is no padding. Again, the compiler can override. Also, if they've added an alignment mechanism to C++11, then that could render much of what I said moot on such a system. – Dave S Sep 01 '11 at 11:35
2

The relevant text is 5.3.3/2 "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."

An implementation is allowed to add extra bytes for the purposes of array bound checks (e.g. "this is the 5th array member out of a total of 12", as this is within the leeway granted here and not explicitly banned by any other requirement.

(Presumably, that implementation would also store a "1 out of 1" indication for structs that aren't part of an array; in C++ the types S and S[1] are quite interchangable)

MSalters
  • 173,980
  • 10
  • 155
  • 350
1

ISO/IEC 14882(10/2008) 1.8.5:

Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size.

This means that an empty struct has a size of 1 although the size of "all data members" (there are none) is zero, as would a zero-length bitfield (according to 9.6.2 this would have to be an unnamed bitfield, though).
Neither really applies though, as you did not ask for an empty struct, and your member is named (so it can't be zero-length).

Similar would be true if your a member was of type void, but 3.9.5 does not allow that ("[...] the void types are incomplete types (3.9.1). Objects shall not be defined to have an incomplete type").

So in short, as you said you are mostly interested about what the standard says: no, the standard does not explicitly define such a case.

However, it also does not forbid the compiler to add padding or apply alignment, and most compilers will pad/align structures to machine word size by default (unless explicitly told otherwise).

Damon
  • 67,688
  • 20
  • 135
  • 185
  • 1
    That's all true, but I think the question isn't worried about empty classes or `std::array` so much as about the general case. – Kerrek SB Sep 01 '11 at 11:52
  • @Damon: Given `struct Empty {};`, `sizeof(Empty) == 1`. Therefore you can still have `sizeof(Empty[4]) == sizeof(std::array)`. – Matthieu M. Sep 01 '11 at 12:42
  • @Matthieu M.: Yes, certainly, and why should it not :-) However, it would be much more interesting if std::array had an is-a relation rather than a has-a relation. In that case, strictly to the letter of the standard, `struct Empty{}` would be allowed (as it would be the base class) to have zero size. – Damon Sep 01 '11 at 12:48
  • ... though "allowed" does not necessarily mean "the compiler will do it", as I've just tested with gcc. The size of a base subobject is still 1 here. – Damon Sep 01 '11 at 12:53
  • @Damon: `sizeof` can never returned `0`. The Empty Base Optimization simply means that given `struct D: Empty { Empty e; };` may have a size of 1, even though it "logically" contain two elements for which size is 1. – Matthieu M. Sep 01 '11 at 13:10
0

If A is a byte then struct will align to the nearest boundary. Rather if A is smaller than a boundary then yes it will be bigger. EX a struct of RGB is the same size as a struct of RGBA.

I don't have sample code that will do that. You have to dump memory and see the holes. If you then assume that everything is size aligned and cast a structure onto a wad of memory you will have bad data. This is why WADs had padding for alignment. As your compositions get more complicated, the ability to close holes by the compiler is diminished. Eventually padding will be introduced and any assumptions of memory layout will become more and more wrong.

Tavison
  • 1,523
  • 1
  • 11
  • 19
  • 1
    I can't reproduce your claims. The types `struct Byte { char x; };` and `struct RGB { char r, g, b; };` have sizes 1 and 3 on my system. – fredoverflow Sep 01 '11 at 11:12
0

A struct can be padded (it's allowed for compilers do whatever they like, for example padding a six-octet type to eight to align with page boundaries). It's unlikely to happen though.

std::array will be bigger, because it stores some extra information in the class, like the array's length. Typing on auto-pilot; read std::vector without thinking.

Nicholas Wilson
  • 9,435
  • 1
  • 41
  • 80