// Compile with "cl /c /Zi /GR- SimplePaddingTest.cpp" // Link with "link SimplePaddingTest.obj /debug /nodefaultlib /entry:main" #include extern "C" using at_exit_handler = void(); int atexit(at_exit_handler handler) { return 0; } struct SimplePadNoPadding { int32_t X; int32_t Y; // No padding anywhere, sizeof(T) = 8 } A; struct SimplePadUnion { union { int32_t X; int64_t Y; struct { int32_t X; // 4 bytes of padding here int64_t Y; } Z; }; // Since the padding occurs at a location that is occupied by other storage // (namely the Y member), the storage will still be considered used, and so // there will be no unused bytes in the larger class. But in the debug // info for the nested struct, we should see padding. // sizeof(SimplePadUnion) == sizeof(Z) == 16 } B; struct SimplePadNoPadding2 { bool A; bool B; bool C; bool D; // No padding anywhere, sizeof(T) = 4 } C; struct alignas(4) SimplePadFields1 { char A; char B; char C; // 1 byte of padding here, sizeof(T) = 4 } E; struct SimplePadFields2 { int32_t Y; char X; } F; struct SimplePadBase { // Make sure this class is 4 bytes, and the derived class requires 8 byte // alignment, so that padding is inserted between base and derived. int32_t X; // No padding here } G; struct SimplePadDerived : public SimplePadBase { // 4 bytes of padding here due to Y requiring 8 byte alignment. // Thus, sizeof(T) = 16 int64_t Y; } H; struct SimplePadEmptyBase1 {}; struct SimplePadEmptyBase2 {}; struct SimplePadEmpty : public SimplePadEmptyBase1, SimplePadEmptyBase2 { // Bases have to occupy at least 1 byte of storage, so this requires // 2 bytes of padding, plus 1 byte for each base, yielding sizeof(T) = 8 int32_t X; } I; struct SimplePadVfptr { virtual ~SimplePadVfptr() {} static void operator delete(void *ptr, size_t sz) {} int32_t X; } J; struct NonEmptyBase1 { bool X; }; struct NonEmptyBase2 { bool Y; }; struct SimplePadMultiInherit : public NonEmptyBase1, public NonEmptyBase2 { // X and Y from the 2 bases will get squished together, leaving 2 bytes // of padding necessary for proper alignment of an int32. // Therefore, sizeof(T) = 2 + 2 + 4 = 8 int32_t X; } K; struct SimplePadMultiInherit2 : public SimplePadFields1, SimplePadFields2 { // There should be 1 byte of padding after the first class, and // 3 bytes of padding after the second class. int32_t X; } L; struct OneLevelInherit : public NonEmptyBase1 { short Y; }; struct SimplePadTwoLevelInherit : public OneLevelInherit { // OneLevelInherit has nested padding because of its base, // and then padding again because of this class. So each // class should be 4 bytes, yielding sizeof(T) = 12. int64_t Z; } M; struct SimplePadAggregate { NonEmptyBase1 X; int32_t Y; // the presence of X will cause 3 bytes of padding to be injected. SimplePadFields1 Fields; } N; struct SimplePadVtable1 { static void operator delete(void *ptr, size_t sz) {} virtual ~SimplePadVtable1() {} virtual void A1() {} virtual void B1() {} } O; struct SimplePadVtable2 { static void operator delete(void *ptr, size_t sz) {} virtual ~SimplePadVtable2() {} virtual void X2() {} virtual void Y2() {} virtual void Z2() {} } P; struct SimplePadVtable3 { static void operator delete(void *ptr, size_t sz) {} virtual ~SimplePadVtable3() {} virtual void Foo3() {} virtual void Bar3() {} virtual void Baz3() {} virtual void Buzz3() {} } Q; struct SimplePadMultiVTables : public SimplePadVtable1, public SimplePadVtable2, public SimplePadVtable3 { ~SimplePadMultiVTables() override {} static void operator delete(void *ptr, size_t sz) {} // SimplePadVtable1 overrides void A1() override {} // SimplePadVtable2 overrides void Y2() override {} void Z2() override {} // SimplePadVtable3 overrides void Bar3() override {} void Baz3() override {} void Buzz3() override {} } R; int main(int argc, char **argv) { return 0; }