C++ object memory layout

1.7k views Asked by At

I am trying to understand the object layout for C++ in multiple inheritance. For this purpose, I have two superclasses A, B and one subclass C. What I expected to see when trying dumping it was: vfptr | fields of A | vfptr | fields of B | fields of C.

I get this model but with some zeros that I don't understand. Here is the code I am trying

    #include <iostream>

    using namespace std;

    class A{
       public:
       int a;
       A(){ a = 5; }
       virtual void foo(){ }
    }; 

    class B{
       public:
       int b;    
       B(){ b = 10; }
       virtual void foo2(){ }
    };

    class C : public A, public B{
       public:
       int c;    
       C(){ c = 15; a = 20;}
       virtual void foo2(){ cout << "Heeello!\n";}
    };

   int main()
  {
    C c;
    int *ptr;

ptr = (int *)&c;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;

       return 0;
   }

And here is the output I get:

4198384     //vfptr
0
20          // value of a
0
4198416     //vfptr
0
10          // value of b
15          // value of c

What is the meaning of the zeros in between? Thanks in advance!

6

There are 6 answers

2
Enrico Granata On BEST ANSWER

That depends upon your compiler. With clang-500, I get:

191787296
1
20
0
191787328
1
10
15
1785512560

I am sure there's a GDB way too, but this is what I get if I dump pointer-sized words with LLDB at the address of the class object:

0x7fff5fbff9d0: 0x0000000100002120 vtable for C + 16
0x7fff5fbff9d8: 0x0000000000000014
0x7fff5fbff9e0: 0x0000000100002140 vtable for C + 48
0x7fff5fbff9e8: 0x0000000f0000000a

This layout seems sensible, right? Just what you expect. The reason why that doesn't show as clean in your program as it does in the debugger is that you are dumping int-sized words. On a 64-bit system sizeof(int)==4 but sizeof(void*)==8

So, you see your pointers split into (int,int) pairs. On Linux, your pointers don't have any bit set beyond the low 32, on OSX my pointers do - hence the reason for the 0 vs. 1 disparity

0
HappyTran On

If you use MVSC, you can dump all memory layout of all class in your solution with -d1reportAllClassLayout like that:

cl -d1reportAllClassLayout main.cpp

Hope it helpful to you

0
Tony the Pony On

Hard to tell without knowing your platform and compiler, but this might be an alignment issue. In effect, the compiler might attempt to align class data along 8-byte boundaries, with zeroes used for padding.

Without the above details, this is merely speculation.

0
Ferenc Deak On

this is hugely architecture and compiler dependant... Possibly for you the size of a pointer might not be the size of an int... What architecture/compiler are you using?

1
barak manos On

If you're working on a 64-bit system, then:

  • The first zero is the 4 most-significant-bytes of the first vfptr.

  • The second zero is padding, so that the second vfptr will be aligned to an 8-byte address.

  • The third zero is the 4 most-significant-bytes of the second vfptr.

You can check if sizeof(void*) == 8 in order to assert that.

0
typ1232 On

This is completely dependant on your compiler, system, bitness.

The virtual table pointer will have the size of a pointer. This depends on whether you are compiling your file as 32-bit or 64-bit. Pointers will also be aligned at a multiple address of their size (like any type will typically be). This is probably why you are seeing the 0 padding after the 20.

The integers will have the size of an integer on your specific system. This is usually always 32-bit. Note that if this isn't the case on your machine you will get unexpected results because you are increasing your ptr by sizeof(int) with pointer arithmetic.