It is a simple question. Code first.
struct A {
int x;
};
struct B {
bool y;
};
struct C {
int x;
bool y;
};
In main function, I call
cout << " bool : " << sizeof(bool) <<
"\n int : " << sizeof(int) <<
"\n class A : " << sizeof(A) <<
"\n class B : " << sizeof(B) <<
"\n class C : " << sizeof(C) << "\n";
And the result is
bool : 1
int : 4
class A : 4
class B : 1
class C : 8
Why is the size of class C 8 instead of 5?
Note that this is compiled with gcc in MINGW 4.7 / Windows 7 / 32 bit machine.
The alignment of an aggregate is that of its strictest member (the member with the largest alignment requirement). In other words the size of the structure is a multiple of the alignment of its strictest (with the largest alignment requirement) member.
struct D
{
bool a;
// will be padded with char[7]
double b; // the largest alignment requirement (8 bytes in my environment)
};
The size of the structure above will be 16 bytes because 16 is a multiple of 8. In your example the strictest type is int aligning to 4 bytes. That's why the structure is padded to have 8 bytes. I'll give you another example:
struct E
{
int a;
// padded with char[4]
double b;
};
The size of the structure above is 16. 16 is multiple of 8 (alignment of double in my environment).
I wrote a blog post about memory alignment for more detailed explanation
http://evpo.wordpress.com/2014/01/25/memory-alignment-of-structures-and-classes-in-c-2/
Aligning structures to the size of a word, which is 4 bytes here.
Looking at the definition of your struct, you have 1 byte value followed by 4 byte Integer. This integer needs to be allocated on 4 byte boundary, which will force compiler to insert a 3 byte padding after your 1 byte bool. Which makes the size of struct to 8 byte. To avoid this you can change order of elements in the struct.
Also for two sizeof calls returning different values, are you sure you do not have a typo here and you are not taking size of pointer or different type or some integer variable.
Answered by Rohit J on struct size is different from typedef version?
Related
I'm using the example in C++14 ยง3.11/2:
struct B { long double d; };
struct D : virtual B { char c; }
After running the snippet below in clang, g++ and VS2015
#include <iostream>
struct B { long double d; };
struct D : /*virtual*/ B { char c; };
int main()
{
std::cout << "sizeof(long double) = " << sizeof(long double) << '\n';
std::cout << "alignof(long double) = " << alignof(long double) << '\n';
std::cout << "sizeof(B) = " << sizeof(B) << '\n';
std::cout << "alignof(B) = " << alignof(B) << '\n';
std::cout << "sizeof(D) = " << sizeof(D) << '\n';
std::cout << "alignof(D) = " << alignof(D) << '\n';
}
I got the following results:
clang g++ VS2015
sizeof(long double) 16 16 8
alignof(long double) 16 16 8
sizeof(B) 16 16 8
alignof(B) 16 16 8
sizeof(D) 32 32 16
alignof(D) 16 16 8
Now, after uncommenting the virtual in the definition of struct D in the code above and running the code again for clang, g++ and VS2015, I obtained the following results:
clang g++ VS2015
sizeof(long double) 16 16 8
alignof(long double) 16 16 8
sizeof(B) 16 16 8
alignof(B) 16 16 8
sizeof(D) 32 32 24
alignof(D) 16 16 8
I have no doubts about the results obtained above, with one single exception: why did the sizeof(D) increased from 16 to 24 in VS2015?
I know this is implementation defined, but there might be a reasonable explanation for this increase in size. This is what I'd like to know if possible.
If you actually make use of the virtual aspect of virtual inheritance, I think the need for the vtable pointer becomes clear. One item in the vtable is likely the offset of the start of B from the start of D.
Assume E inherits virtually from B and F inherits from both E and D such that the D inside an F ends up using the B inside the E for its base class. In a method of D that doesn't know it is a base class of F how could you find members of B without info stored in the vtable?
So clang and G++ changed 8 bytes of padding into a vtable pointer and you thought there was no change. But VS2015 never had that padding, so it needed to add 8 bytes for vtable pointer.
Maybe a compiler notices that the only use of the vtable pointer is in an inefficient scheme for computing the base pointer. So maybe that is optimized into simply having a base pointer instead of a vtable pointer. But that would not change the need for the 8 bytes.
When there is a virtual base object, the location of the base object relative to the address of a derived object is not statically predictable. Notably, if you extend your class hierarchy a bit it becomes clear that there can be multiple D subobjects which still need to reference just one B base object:
class I1: public D {};
class I2: public D {};
class Most: public I1, public I2 {};
You can get a D* from a Most object by either converting first to I1 or first to I2:
Most m;
D* d1 = static_cast<I1*>(&m);
D* d2 = static_cast<I2*>(&m);
You'll have d1 != d2, i.e., there are genuinely two D subobjects, but static_cast<B*>(d1) == static_cast<B*>(d2), i.e., there is just one B subobject. To determine how to adjust d1 and d2 to find a pointer to the B subobject a dynamic offset is needed. The information on how to determine this offset needs to be stored somewhere. The storage for this information is the likely source of the extra 8 bytes.
I don't think the object layout for types in MSVC++ is [publicly] documented, i.e., it is impossible to tell for sure what they are doing. From the looks of it they embed a 64 bit object to be able to tell where the base object lives relative to the address of the derived object (a pointer to some type information, a pointer to a base, an offset to the base, something like that). The other 8 byte most likely originate from the need to store a char plus some padding to have the object aligned at a suitable boundary. That seems similar to what the other two compilers do except that they used 16 bytes for long double to start with (probably it is just 10 bytes padded to a suitable alignment).
To understand how the C++ object model could work, you might want to have a look at Stan Lippman's "Inside the C++ Object Model". It is a bit dated but describes potential implementation techniques. Whether MSVC++ uses any of them I don't know but it gives ideas what might be used.
For the object model used by gcc and clang you can have a look at the Itanium ABI: they essentially use the Itanium ABI with the minor adjustments to the actually used CPU.
In visual studio, the default behaviour is that all structs are aligned along a 8 byte boundary. i.e.even if you do
struct A {
char c;
}
and then check sizeof(A), you will see that it is 8 bytes.
Now, in your case, when you changed the type of inheritance of struct D to be virtual, the compiler has to do something extra to accomplish this. First, it creates a virtual table for the struct D. What does this vtable contain? It contains a single pointer to the offset of struct B in memory.Next, it adds a vptr at the head of struct D which points to the newly created vtable.
Hence, now struct D should look like:
struct D : virtual B { void* vptr; char c; }
So, the size of D will be:
sizeof (long double) + sizeof (void*) + sizeof (char) = 8 + 8 + 1 = 17
This is where the boundary alignment we discussed in the beginning comes in. Since all structs have to be aligned to an 8 byte boundary and struct D is only 17 bytes, the compiler adds 7 padding bytes to the struct to make it aligned to a 8 byte boundary.
So the size now becomes:
Size of D = Size of elements of D + Padding bytes for byte alignment = 17 + 7 = 24 bytes.
I was testing a class alignment and found strange behavior. I tested it with VS2012 compiler setting 4 and 8 bytes alignment setting but in each case output is same.
class Alignemnt{
public:
Alignemnt():a(){}
int a;
};
class Alignemnt_1{
public:
int a;
char array[2];
};
class Alignemnt_2{
public:
int a;
char array[2];
int x;
};
std::cout << "Sizeof(Alignemnt) :" <<sizeof(Alignemnt) << std::endl;
std::cout << "Sizeof(Alignemnt_1) :" <<sizeof(Alignemnt_1) << std::endl;
std::cout << "Sizeof(Alignemnt_2) :" <<sizeof(Alignemnt_2) << std::endl;
Every time output is:
Sizeof(Alignemnt) : 4
Sizeof(Alignemnt_1) : 8
Sizeof(Alignemnt_2) : 12
I think, Alignemnt_2 size should be 16 byte.
I assume you are referring to the /Zp switch, which lets you control maximum struct member alignment:
When you specify this option, each structure member after the first is stored on either the size of the member type or n-byte boundaries (where n is 1, 2, 4, 8, or 16), whichever is smaller.
Since you are not using a struct member with an alignment of more than 4 bytes (sizeof(int) and alignof(int) is both 4), all settings of 4 bytes and above will lead to exactly the same behavior.
If you want to specify the exact alignment of a structure member, consider using the standard C++ alignas which allows you to specify the exact alignment a member is supposed to have (VS 2012 should support it iirc).
See the result of using alignas.
Alignment shouldn't change the size of your object, just the starting address of the objects. For instance, an 8 byte aligned object could be at address 0x100000 or 0x100008, or really any address ending in 0 or 8 when written in hex but not 0x100004.
No.
Aligment 2 is fine.
You have 2 chars next to each other, that means you have 2 out of 4 bytes used. The packing will align it to 4 bytes, and then you will end up with 4 + 4 +4 .
If you want to end up to 16 you can try the following declaration :
{
char a;
int b;
char c;
int d;
}
This question already has an answer here:
Size of class with virtual function
(1 answer)
Closed 8 years ago.
Have a look at these 2 cases:
class A {
public:
int a;
A () { a = 10;}
void foo () {std::cout << "a = " << a << std::endl;}
};
Here sizeof(A) gives 4 bytes, which makes sense.
class A {
public:
int a;
A () { a = 10;}
virtual void foo () {std::cout << "a = " << a << std::endl;}
};
Here sizeof(A) gives 16 bytes as opposed to 12 bytes (4 + 8 for pointer).
Is there any explanation in terms of memory alignment for this ?
It's up to the compiler how virtual functions are implemented, but what's likely happening here is it wants/needs to align the 8-byte pointer to the virtual dispatch table on a multiple-of-8 memory address. Then there's either { 4 bytes a, 4 padding, 8 vdt pointer } or { 8 vdt pointer, 4 bytes a, 4 padding } - the latter's less obvious, but consider that arrays of A need to be contiguous and spaced per sizeof(A), so 12's rounded up to 16 given the 8-byte alignment.
FIRST in virtual dispatch table, visual functions need a pointer size , in 32 bits computer, the size of pointer is 4 bytes, int 64 bits it's 8 bytes. so I think your computer is 64 bits.
SECOND the sizeof(A) should consider the padding and memory alignment .
so 16 bytes is arranged like that: 4 bytes(int a) + 8 bytes(a virtual function pointer int 64 bits) + 4 bytes padding(because the max size of elements in A is the virtual function pointer which is 8 bytes, so the sizeof(A)should be the integral multiples of 8 bytes )
According to MSDN, the /Zp command defaults to 8, which means 64-bit alignment boundaries are used. I have always assumed that for 32-bit applications, the MSVC compiler will use 32-bit boundaries. For example:
struct Test
{
char foo;
int bar;
};
The compiler will pad it like so:
struct Test
{
char foo;
char padding[3];
int bar;
};
So, since /Zp8 is used by default, does that mean my padding becomes 7+4 bytes using the same example above:
struct Test
{
char foo;
char padding1[7];
int bar;
char padding2[4];
}; // Structure has 16 bytes, ending on an 8-byte boundary
This is a bit ridiculous isn't it? Am I misunderstanding? Why is such a large padding used, it seems like a waste of space. Most types on a 32-bit system aren't even going to use 64-bits, so the majority of variables would have padding (probably over 80%).
That's not how it works. Members are aligned to a multiple of their size. Char to 1 byte, short to 2, int to 4, double to 8. The structure is padded at the end to ensure the members still align correctly when the struct is used in an array.
A packing of 8 means it stops trying to align members that are larger than 8. Which is a practical limit, the memory allocator doesn't return addresses aligned better than 8. And double is brutally expensive if it isn't aligned properly and ends up straddling a cache line. But otherwise a headache if you write SIMD code, it requires 16 byte alignment.
That does not mean every member is aligned on an 8byte boundary. Read a little more carefully:
the smaller member type or n-byte boundaries
The key here is the first part- "smaller member type". That means that members with less alignment might be aligned less, effectively.
struct x {
char c;
int y;
};
std::cout << sizeof(x);
std::cout << "offsetof(x, c) = " << offsetof(x, c) << '\n';
std::cout << "offsetof(x, c) = " << offsetof(x, y) << '\n';
This yields 8, 0, 4- meaning that in fact, the int is only padded to a 4byte alignment.
why the size of the class cl1 in the following code is 8 but not 5, while the size of class cl2 is 1?
class cl1 {
public:
int n;
char cb;
cl1();
~cl1();
};
class cl2 {
public:
char cb;
cl2();
~cl2();
};
The compiler is free to insert padding in between and after class members in order to ensure that variables are properly aligned, etc. Exactly what padding is inserted is up to the implementation. In this case, I'd guess that the compiler is adding 3 bytes of padding after cl1::cb, perhaps to ensure that the next variable in memory is aligned on a 4-byte boundary.
The largest member of cl1 (n) is 4 bytes, so the size of cl1 is padded up to the nearest 4 bytes (8 in this case) so that an array of cl1 objects does not create n members which are not aligned to 4-byte addresses. Most processors really hate misaligned multi-byte values, either suffering performance losses (two memory cycles to access one value) or outright crashes (alignment exceptions).
There is no guarantee that this will be consistent from compiler to compiler or platform to platform.
This is all due to padding. More info can be found, for example, here
The thing is that the addresses of both the object and its members should be properly aligned for OS and Hardware - specific reasons. Thus the result. The problem of padding is complicated by the fact that objects in an array must be located consecutively, without any space in between, and ALL should be properly aligned.
It is because of structure padding by the compiler. If you want to remove the padding, try #pragma pack(1) and you should get 5 and 1 as expected.
While you're exploring the size of struct and how padding is done, let me tell you an interesting thing. The size of struct not only depends on the members, but also on the order of their declaration. For example, size of the following structs is different, even though both has same number of members of same types, the only difference is the order of their declaration!
struct A
{
int a;
char b;
char c;
};
struct B
{
char b;
int a;
char c;
};
cout << "sizeof(A) = " << sizeof(A) << endl;
cout << "sizeof(B) = " << sizeof(B) << endl;
Output:
sizeof(A) = 8
sizeof(B) = 12
Online Demo at Ideone: http://www.ideone.com/8OoxX