3

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!

KillianDS
  • 16,936
  • 4
  • 61
  • 70
ginou
  • 73
  • 1
  • 6
  • 1
    There's no such thing as "object layout for C++". There is "object layout that your compiler happens to produce on your platform this week". – n. m. could be an AI Feb 09 '14 at 20:06
  • 1
    _`What is the meaning of the zeros in between? Thanks in advance!`_ Alignment padding. That's compiler specific! – πάντα ῥεῖ Feb 09 '14 at 20:06
  • @n.m. It better be the same layout that the same compiler produces for this platform last week, and next week. It also better be the same layout that a different compiler will produce for this same platform if you want at least some minimal interaction between compilers. – David Rodríguez - dribeas Feb 09 '14 at 21:32
  • This is dependent on the architecture and the platform, you should add those to the question. For example, the layout for windows/64 and linux/32 in intel will be very different, and will most probably be different than sparc/64 in Solaris... – David Rodríguez - dribeas Feb 09 '14 at 21:33
  • @DavidRodríguez-dribeas That would be indeed very nice, however nothing of this sort is guaranteed. – n. m. could be an AI Feb 09 '14 at 21:56
  • @n.m.: It all depends on who you consider to be a guarantor. The C++ ABI of the platform provides stricter guarantees than the standard does. Any 4.x version of gcc, any clang compiler and any intel compiler in linux 32 or linux 64 will have exactly the same layout. Anyways the *this week* remark in your comment is much of a hyperbole, or do you really mean that you need to rebuild all your code and shared libraries at once (or at least within the same week) for your compiler/linker to make them work together? – David Rodríguez - dribeas Feb 10 '14 at 14:24
  • @DavidRodríguez-dribeas Some very popular platforms (wink, nudge, *including Linux*, wink, nudge) possess sets of incompatible compilers/ABIs (sometimes the same compiler complies with different ABIs depending on command line options). While ABIs don't normally change each week, they do change and this has to happen during *some* week. – n. m. could be an AI Feb 10 '14 at 14:40

6 Answers6

2

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

Enrico Granata
  • 3,303
  • 18
  • 25
2

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?

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167
2

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.

barak manos
  • 29,648
  • 10
  • 62
  • 114
1

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.

Tony the Pony
  • 40,327
  • 71
  • 187
  • 281
1

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.

typ1232
  • 5,535
  • 6
  • 35
  • 51
1

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

HappyTran
  • 503
  • 6
  • 9