Summary: How does the compiler statically determine the size of a C++ class during compilation?
Details:
I'm trying to understand what the rules are for determining how much memory a class will use, and also how the memory will be aligned.
For example the following code declares 4 classes. The first 2 are each 16 bytes. But the 3 is 48 bytes, even though it contains the same data members as the first 2. While the fourth class has the same data members as the third, just in a different order, but it is 32 bytes.
#include <xmmintrin.h>
#include <stdio.h>
class TestClass1 {
__m128i vect;
};
class TestClass2 {
char buf[8];
char buf2[8];
};
class TestClass3 {
char buf[8];
__m128i vect;
char buf2[8];
};
class TestClass4 {
char buf[8];
char buf2[8];
__m128i vect;
};
TestClass1 *ptr1;
TestClass2 *ptr2;
TestClass3 *ptr3;
TestClass4 *ptr4;
int main() {
ptr1 = new TestClass1();
ptr2 = new TestClass2();
ptr3 = new TestClass3();
ptr4 = new TestClass4();
printf("sizeof TestClass1 is: %lu\t TestClass2 is: %lu\t TestClass3 is: %lu\t TestClass4 is: %lu\n", sizeof(*ptr1), sizeof(*ptr2), sizeof(*ptr3), sizeof(*ptr4));
return 0;
}
I know that the answer has something to do with alignment of the data members of the class. But I am trying to understand exactly what these rules are and how they get applied during the compilation steps because I have a class that has a __m128i
data member, but the data member is not 16-byte aligned and this results in a segfault when the compiler generates code using movaps
to access the data.
For POD (plain old data), the rules are typically:
The size of the structure is the value of S when the above is done.
Additionally:
Consider your TestClass3
:
char buf[8]
requires 8 bytes and alignment 1, so S is increased by 8 to 8, and A remains 1.__m128i vect
requires 16 bytes and alignment 16. First, S must be increased to 16 to give the right alignment. Then A must be increased to 16. Then S must be increased by 16 to make space for vect
, so S is now 32.char buf2[8]
requires 8 bytes and alignment 1, so S is increased by 8 to 24, and A remains 16.So the size of TestClass3
is 32 bytes.
For elementary types (int
, double
, et cetera), the alignment requirements are implementation dependent and are largely determined by the hardware. On many processors, it is faster to load and store data when it has a certain alignment (usually when its address in memory is a multiple of its size). Beyond this, the rules above follow largely from logic; they put each member where it must be to satisfy alignment requirements without using more space than necessary.