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;
}
Related
when is simply execute
cout << sizeof(string);
i got 8 as answer.
now i am having a structure
typedef struct {
int a;
string str;
} myType;
and i am executing
cout << sizeof(myType);
i got 16 as the answer.
now i made a change in my structure
typedef struct {
int a, b;
string str;
} myType;
and i am executing
cout << sizeof(myType);
i got 16 as the answer!!!. How? What is happening?
Perhaps padding is happening. E.g. sizeof(int) can be 4 bytes and compiler can add 4 bytes after a for the sake of data alignment. The layout could be like this:
typedef struct {
int a; // 4 bytes
// 4 bytes for padding
string str; // 8 bytes
} myType;
typedef struct {
int a; // 4 bytes
int b; // 4 bytes
string str; // 8 bytes
} myType;
Looks like 8 byte alignment.
So if you have any data type that has less than 8 bytes, it will still use 8 bytes.
I assume the pointer is 8 byte, whereas the ints are only 4 bytes each.
You can force 1 byte alignment using code like outlined here Struct one-byte alignment conflicted with alignment requirement of the architecture? . You should then get different size for first case.
It's called structure packing to achieve optimal memory alignment.
See The Lost Art of C Structure Packing to understand the how and why. It's done the same way in both C and C++.
In C/C++ structs are "packed" in byte chunks. You can specify which size your structs should be packed.
Here a reference: http://msdn.microsoft.com/en-us/library/2e70t5y1.aspx
I have made the following code as an example.
#include <iostream>
struct class1
{
uint8_t a;
uint8_t b;
uint16_t c;
uint32_t d;
uint32_t e;
uint32_t f;
uint32_t g;
};
struct class2
{
uint8_t a;
uint8_t b;
uint16_t c;
uint32_t d;
uint32_t e;
uint64_t f;
};
int main(){
std::cout << sizeof(class1) << std::endl;
std::cout << sizeof(class2) << std::endl;
std::cout << sizeof(uint64_t) << std::endl;
std::cout << sizeof(uint32_t) << std::endl;
}
prints
20
24
8
4
So it's fairly simple to see that one uint64_t is as large as two uint32_t's, Why would class 2 have 4 extra bytes, if they are the same except for the substitution of two uint32_t's for an uint64_t.
As it was pointed out, this is due to padding.
To prevent this, you may use
#pragma pack(1)
class ... {
};
#pragma pack(pop)
It tells your compiler to align not to 8 bytes, but to one byte. The pop command switches it off (this is very important, since if you do that in the header and somebody includes your header, very weird errors may occur)
Why does an uint64_t needs more memory than 2 uint32_t's when used in a class?
The reason is padding due to alignment requirements.
On most 64-bit architectures uint8_t has an alignment requirement of 1, uint16_t has an alignment requirement of 2, uint32_t has an alignment requirement of 4 and uint64_t has an alignment requirement of 8. The compiler must ensure that all members in a structure are correctly aligned and that the size of a structure is a multiple of it's overall alignment requirement. Furthermore the compiler is not allowed to re-order members.
So your structs end up laid out as follows
struct class1
{
uint8_t a; //offset 0
uint8_t b; //offset 1
uint16_t c; //offset 2
uint32_t d; //offset 4
uint32_t e; //offset 8
uint32_t f; //offset 12
uint32_t g; //offset 16
}; //overall alignment requirement 4, overall size 20.
struct class2
{
uint8_t a; //offset 0
uint8_t b; //offset 1
uint16_t c; //offset 2
uint32_t d; //offset 4
uint32_t e; //offset 8
// 4 bytes of padding because f has an alignment requirement of 8
uint64_t f; //offset 16
}; //overall alignment requirement 8, overall size 24
And how to prevent this?
Unfortunately there is no good general solution.
Sometimes it is possible to reduce the amount of padding by re-ordering fields, but that doesn't help in your case. It just moves the padding around in the structure. A structure with a field requiring 8 byte alignment will always have a size that is a multiple of 8. Therefore no matter how much you rearrange the fields your structure will always have a size of at least 24.
You can use compiler-specific features such as #pragma pack or __attribute((packed)) to force the compiler to pack the structure more tightly than normal alignment requirements would allow. However, as well as limiting portability, this creates a problem when taking the address of a member or binding a reference to the member. The resulting pointer or reference may not satisfy the alignment requirements and therefore may not be safe to use.
Different compilers vary in how they handle this problem. From some playing around on godbolt.
g++ 9 through 11 will refuse to bind a reference to a packed member and give a warning when taking the address.
clang 4 through 11 will give a warning when taking the address, but will silently bind a reference and pass that reference across a compilation unit boundary.
Clang 3.9 and earlier will take the address and bind a reference silently.
g++ 8 and earlier and clang 3.9 and earlier (down to the oldest version on godbolt) will also refuse to bind a reference, but will take the address with no warning.
icc will bind a pointer or take the address without producing any warnings in either case (though to be fair intel processors support unaligned access in hardware).
The rule for alignment (on x86 and x86_64) is generally to align a variable on it's size.
In other words, 32-bit variables are aligned on 4 bytes, 64-bit variables on 8 bytes, etc.
The offset of f is 12, so in case of uint32_t f no padding is needed, but when f is an uint64_t, 4 bytes of padding are added to get f to align on 8 bytes.
For this reason it is better to order data members from largest to smallest. Then there wouldn't be any need for padding or packing (except possibly at the end of the structure).
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?
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