ChrisMM
ChrisMM

Reputation: 10019

Will sizeof always be the same?

I have a quick question about class structuring, padding, and the resulting sizeof the class. In the below example, on every compiler I've tested, the result is always 40 bytes for sizeof A, which makes sense to me.

#include <iostream>
class A {
    int a, b; // 4 + 4
    short c;  // + 2
    double f; // not currently 8 byte aligned. Currently 10 bytes, so pad 6 extra bytes, so: + 6 + 8
    char w;   // + 1
    bool d;   // + 1
    double g; // not currently 8 byte aligned. Currently 26 bytes, so pad 6 extra bytes, so: + 6 + 8

    // 4 + 4 + 2 + 6 + 8 + 1 + 1 + 6 + 8 = 40
};

int main() {
    std::cout << sizeof( A );
}

My question is, will this always be true? (assume the alignof and sizeof each individual member doesn't change). I know I can reorder it, so that the doubles come first, and it shrinks down to 32 bytes; but can a compiler make this decision? Or is it the always the programmer's responsibility? (I'm assuming the compiler can't reorder)

Upvotes: 5

Views: 530

Answers (4)

eerorika
eerorika

Reputation: 238291

Will sizeof always be the same?

sizeof is compile time constant. So for any program that has been compiled, the sizeof will not change between executions. There is no such guarantee for different compilations of the program however. In fact, when program is compiled for another system, it is quite typical for sizeof and alignof of even fundamental types to be different.

I know I can reorder ... can a compiler make this decision?

There are restrictions for standard layout classes. The first member is guaranteed to have the same address as the super object. Also, for any such classes with same types of members in same order at the beginning of declaration order, that "common initial sequence" may be accessed through separate members of union, which in practice mean that they must have the same address, which effectively prevents any re-ordering of members because compiler cannot know what other classes with potentially shared common initial sequences there may be. A is a standard layout class.

These restrictions don't apply to non-standard layout classes, with which the compiler is allowed to be more relaxed. As far as I know, the language doesn't prevent the compiler from choosing the order of members of non-standard layout classes. But in practice, in order to link together object files that have been compiled separately, those object files must conform to the same binary interface, i.e. they need to have the same representation for types. If the compiler used one layout for one compilation, and different layout for another, that would break the ABI. So, whatever order the compiler chooses, it should stick to it. And any compiler that intends to be compatible, should use that same ABI. For what it's worth the Itanium ABI, used by GCC, specifies:

2.4 Non-POD Class Types

II. Allocation of Members Other Than Virtual Bases

For each data component D (first the primary base of C, if any, then the non-primary, non-virtual direct base classes in declaration order, then the non-static data members and unnamed bit-fields in declaration order) ...


Or is it the always the programmer's responsibility? (I'm assuming the compiler can't reorder)

It's best for the programmer to assume that sub objects are in declaration order, and to choose that order in a way to minimise padding. It's best to not assume the order of sub objects for purposes of accessing memory of non-standard layout classes.

Upvotes: 3

NathanOliver
NathanOliver

Reputation: 180415

sizeof(A) in the execution of your program will always be the same. If you change the order of the members or how A is packed and recompile, then you can/will get a different value. If you compile with a different compiler the size can also change. It can also change on different machines using the same compiler because different machines can have different sizes for the fundamental types.

Long story short, if you depend on your class being a specific size then add a static_assert that checks for that. That way if it does change, you'll get a nice compiler error instead of possible UB.

I know I can reorder it, so that the doubles come first, and it shrinks down to 32 bytes; but can a compiler make this decision?

No, the compiler cannot reorder the members for better packing since your class is a standard layout class and all members must be laid out in memory in declared order.

Upvotes: 5

Mark B
Mark B

Reputation: 96233

The compiler is not allowed to reorder the attributes in your class (this order is used when constructing and deconstructing members so it would potentially change the meaning of your program to do so).

However you also can't count on the result of sizeof always being the same. What if there came about an architecture for which a 64 bit int made more sense than 32 bit? In that case the size would be larger.

Upvotes: 1

Bathsheba
Bathsheba

Reputation: 234635

The compiler is not allowed to reorder the members because they all have the same access level. So if there was, for example, a public member then the compiler could reorder your member variables.

Reference: https://timsong-cpp.github.io/cppwp/class.mem#19

The C++ standard offers no guarantees for the size of your class, other than it must be such that the members are individually addressable.

Upvotes: 5

Related Questions