class / struct member Alignment, Data Packing under 64bits program - c++

class A {
int a;
public:
virtual ~A() {}
};
class B : public A {
int b;
};
int main(int argc, char* argv[])
{
cout << sizeof(B) << endl;
return 0;
}
(Based on 64bits program), I notice the differences of the values under Visual Studio and gcc, respectively are 24 and 16.
By analyzing, the virtual table costs 8 bytes, int a and int b respectively is 4 bytes. So the alignment for VS is 8 but for gcc is 4.
What does cause the difference, how does the C++ standard say?
struct C {
char a;
int b;
char c;
};
int main(int argc, char* argv[])
{
cout << sizeof(C) << endl;
return 0;
}
Moreover, under VS, the size of this struct is 12 that implies the alignment is 4, different from the alignment for class B under VS.
Why?

You will find that alignof(A) == 8 && sizeof(A) == 16 on both compilers, laid out as 8 bytes for a pointer, 4 bytes for int A::a, and 4 bytes of padding.
Since A is a base class, it is a potentially overlapping subobject of any B objects. This means that the padding can be reused.
gcc/clang (More specifically, things that follow the Itanium ABI) have to allocate int B::b into the 4 bytes of padding in the base class, so sizeof(B) is also 16 (but alignof(B) == 8 still).
MSVC (and clang compiling for Windows) follow a different ABI, which happens to not reuse the tail padding, so the layout of B looks like 8 bytes for a pointer, 4 bytes for int A::a, 4 bytes of padding (inherited from A), 4 bytes for int B::b, and 4 more bytes of padding.
As for your last questions, typically vtables are implemented as a pointer stored at the front of each object. This pointer will usually have the size an alignment requirement of 8 on a 64 bit platform. C would be comparable if it looked like:
struct C {
void* p;
char a;
// 3 bytes padding
int b;
char c;
// 7 bytes padding to alignment of 8
};
static_assert(sizeof(C) == 24 && alignof(C) == 8);

With the other's help, I finally figure it out.
alignof(B) under VS and GCC are same which is 8.
1. Why sizeof(B) are different?
Because they store the virtual function pointer (vptr) at different places, for VS at beginning and for GCC at the end. Something like this,
//B for VS
class B{
class A{
void* vptr;
int a;
};
int b;};
//B for GCC
class B{
int a;
int b;
void* vptr;
};
For VS, sizeof(B) = sizeof(vptr) + (sizeof(int a) padding to 8) + (sizeof(int b) padding to 8) = 24.
For GCC, sizeof(B) = (sizeof(int a)+sizeof(int b) padding to 8) + sizeof(vptr) = 16.
2. Why alignof(C) is 4?
Because there is virtual function in struct C. If you add virutal ~C(){} for C, alignof(C) would be 8 either.

Related

Packing unions/structure to avoid padding

I have a structure that looks like this:
struct vdata {
static_assert(sizeof(uint8_t *) == 8L, "size of pointer must be 8");
union union_data {
uint8_t * A; // 8 bytes
uint8_t B[12]; // 12 bytes
} u;
int16_t C; // 2 bytes
int16_t D; // 2 bytes
};
I would like to make this 16 bytes, but GCC is telling me it is 24, as the union is padding to 16 bytes.
I would like to put vdata into a large std::vector. From my understanding, there should be no issue with alignment if this were 16 bytes, since the pointer would always be 8 byte aligned.
I understand that I can force this to be packed using __attribute__((__packed__)) in GCC. But I would like to know if there is a portable and standard compliant way to get this to be 16 bytes?
Edit: Ideas
Idea 1: split up the B array.
struct vdata {
union union_data {
uint8_t * A; // 8 bytes
uint8_t B[8]; // 8 bytes
} u;
uint8_t B2[4]; // 4 bytes
int16_t C; // 2 bytes
int16_t D; // 2 bytes
};
Could B2 elements be reliably accessed from a pointer of B? Is that defined behavior?
Idea 2: store pointer as byte array and memcpy as necessary (#Eljay)
struct vdata {
union union_data {
std::byte A[sizeof(uint8_t*)]; // 8 bytes
uint8_t B[12]; // 12 bytes
} u;
int16_t C; // 2 bytes
int16_t D; // 2 bytes
};
Would there be a performance penalty for accessing the pointer, or would it be optimized out? (Assuming GCC x86).
You could change A to std::byte A[sizeof(uint8_t*)]; and then std::memcpy the pointer into A and out of A.
Worth commenting as to what is going on, and that these extra hoops are to avoid padding bytes.
Also adding a set_A setter and get_A getter may be very helpful.
struct vdata {
union union_data {
std::byte A[sizeof(uint8_t*)]; // 8 bytes
uint8_t B[12]; // 12 bytes
} u;
int16_t C; // 2 bytes
int16_t D; // 2 bytes
void set_A(uint8_t* p) {
std::memcpy(u.A, &p, sizeof p);
}
uint8_t* get_A() {
uint8_t* result;
std::memcpy(&result, u.A, sizeof result);
return result;
}
};
Store C+D in the union's array, and provide method access to them:
struct vdata {
static_assert(sizeof(uint8_t *) == 8L, "size of pointer must be 8");
union union_data {
uint8_t * A; // 8 bytes
uint8_t B[16]; // 12 + 2*2 bytes
} u;
int16_t& C() {
return *reinterpret_cast<int16_t*>(static_cast<void*>(&u.B[12]));
}
int16_t& D() {
return *reinterpret_cast<int16_t*>(static_cast<void*>(&u.B[14]));
}
};
Demo (with zero warnings for strict aliasing violations and run-time address sanitization enabled)
Keep in mind that there's no strict aliasing violation when the buffer is char* i.e. single byte type like uint8_t - I mean thankfully because otherwise it would be impossible to create memory pools. If it makes things clearer/safer you can even have an explicit char array buffer:
struct vdata {
union union_data {
uint8_t * A; // 8 bytes
uint8_t B[12]; // 12 bytes
char buf[16]; // 16 bytes - could be std::byte buf[16]
} u;
int16_t& C() { return *(int16_t*)(&u.buf[12]); }
int16_t& D() { return *(int16_t*)(&u.buf[14]); }
};
Regarding alignment The array is 8-aligned due to the address of the union, so positions 12&14 are guaranteed to be 2-aligned which is the requirement for int16_t (even though the string u.B appears in the code).
Alternatively you can force align the structure. The C++ alignas specifier would not be valid here because you want to lower the alignment of your structure, put a pragma directive is possible to give you again 16 bytes:
#pragma pack(4)
struct vdata {
static_assert(sizeof(uint8_t *) == 8L, "size of pointer must be 8");
union union_data {
uint8_t * A; // 8 bytes
uint8_t B[12]; // 12 bytes
} u;
int16_t C; // 2 bytes
int16_t D; // 2 bytes
};
Demo
I'm fairly certain that this one will cause problems.
As far as I understand, the following code would be the most safe one.
The data that specify the type is in the Initial common sequence. Thus you can access it either way (by using cda.C or cdb.C) so it is perfect for determining the type.
Then putting everything in a struct for both cases allows to ensure that each struct layout is independant (thus B can start before next 8 bytes alignment).
#include <cstdint>
#include <iostream>
struct CDA
{
int16_t C; // 2 bytes
int16_t D; // 2 bytes
uint8_t* A; // 8 bytes
};
struct CDB
{
int16_t C; // 2 bytes
int16_t D; // 2 bytes
uint8_t B[12]; // 12 bytes
};
struct vdata {
union union_data {
CDA cda;
CDB cdb;
} u;
};
static_assert(sizeof(uint8_t*) == 8);
static_assert(sizeof(CDA) == 16);
static_assert(sizeof(CDB) == 16);
static_assert(offsetof(vdata::union_data, cda) == offsetof(vdata::union_data, cdb));
static_assert(offsetof(CDA, C) == offsetof(CDB, C));
static_assert(offsetof(CDA, C) == 0);
static_assert(sizeof(vdata) == 16);
int main()
{
std::cout << "sizeof(CDA) : " << sizeof(CDA) << std::endl;
std::cout << "sizeof(CDB) : " << sizeof(CDB) << std::endl;
std::cout << "sizeof(vdata) : " << sizeof(vdata) << std::endl;
}
Usefull source of information:
CppCon 2017: Scott Schurr “Type Punning in C++17: Avoiding Pun-defined Behavior”
Union declaration
std::launder
std::variant
How to decide?
If the size optimization is not that important, I would recommend to use std::variant.
If the size is important but the order is not, then the current solution might be the best choice.
If portability is not so important, then pragma pack solution might be appropriate (remember to reset alignment after the struct definition).
Otherwise, if you really need layout control, then either use:
std::byte array and memcpy (access data with functions)
placement new and std::launder.
In all cases, be sure to have appropriate assertion that verify assumptions you make. I have put many in my sample code but you can adjust depending on your need.
Also, unless you have millions of vdata items or you are on an embedded device, then using 24 bytes instead of 16 might not be a big deal.
You might also use conditionnal define to optimize only for your current compiler. This could be useful to ensure that you have working code (though maybe less optimal) for every target or it can allows to depend on behavior that is undefined from the standard but might be defined on your compiler.

Why object with vptr is 12 bytes longer?

#include <iostream>
class B
{
public:
virtual void f() {std::cout<<"HI";}
int x;
};
class A
{
public:
void f() {std::cout<<"HI";}
int x;
};
int main () {
A a;
B b;
std::cout<<sizeof(a)<<" "<<sizeof(b);
return 0;
}
The output is
4 16
I expected it to be 8 bytes longer - vptr pointer. But for what the rest 4 bytes is used?
I found quite many forum posts (all from some years ago) where people discussed that object from the class with vprt is 4 or 8 bytes longer. I checked also on online C++ shell - output there is the same.
It seems that the pointer to the table of pointers to virtual functions has a size of 8 bytes. So the class B is aligned to the boundary of 8 bytes that is it has 4 additional padding bytes.

Why the sizeof(D) increased by 8 bytes in VS2015 when I derived D from a virtual base?

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.

Class Alignment issue

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;
}

C++ sizeof with bool

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?