How can I understand the fdump-class-hierarchy out

2019-01-23 20:22发布

I'm playing with fdump-class-hierarchy compiler option but I don't know how I can understand the output. What does the "size", "align", "base size" and "base align" mean, and how these are counted? Thanks!

When the code is:

class A
{
public:

private:
    double m_nothing;
    int m_number;
};

The output is:

Class A
   size=16 align=8
   base size=16 base align=8
A (0x406c690) 0

But, if I change the class a little:

class A
{
public:

private:
    int m_number;
    double m_nothing;
};

the output will be:

Class A
   size=16 align=8
   base size=12 base align=8
A (0x406c690) 0

1条回答
家丑人穷心不美
2楼-- · 2019-01-23 21:00

The size and align are the size and alignment of the class when used as complete type. That is, if you create objects whose complete type is that type (like defining variables of that type, or using that type with new).

The size is simply the number of bytes it occupies. So size=16 means when used as complete type, it always occupies 16 bytes.

The alignment tells you where the object may be placed: align=8 means the address of the object must be an integer multiple of 8.

The base size and base align give the size and alignment in case the class is used as base class. The reason why they are different is that the C++ standard allows objects to use less padding when used as base class.

So let's look specifically at your example (I'm assuming that you actually have the int before the double in the first case). I'm also omitting the public and private because here they don't change anything (if you had both public or private data members, they could in principle change something, but I don't know if any compiler takes advantage of that). I'm also guessing the size and alignment of int and double (actually the values I assume are pretty common choice, and explain the values you get).

So in the first case (I assume) you have

class A
{
  int m_number;
  double m_nothing;
};

Now int has size and alignment 4, and double has size and alignment 8.

So let's do the job of the compiler and build our class.

First, we have m_number, which occupies 4 bytes. We have to put the members in the order given, so m_number goes at the beginning of A:

iiii

Up to now, we have size 4 (the four bytes for the int), and alignment 4 (because int has alignment 4). But now we have to add a double (size and alignment 8). Since directly after the int, we are at (relative) address 4, we are not correctly aligned for the double, so we have to add 4 padding bytes (which I'll mark with *) to get to a multiple of 8. Thus we get for our class:

iiii****ffffdffffddd

Now, if the class is used as base class, we are finished. Thus we habe base size=16 and base align=8 (we need an alignment of 8 in order to get the double aligned correctly).

For the complete object, there's another consideration: The standard demands that in arrays, the objects follow each other without a gap in between. That is, the first byte after the object must be correctly aligned for the next object. Which ultimately means that the size of the complete object has to be a multiple of its alignment.

Now the object layout we've found already fulfils that requirement. Therefore we can use it unchanged also for the complete object. Therefore we get size=16 and align=8 for the complete object.

Now consider the case where the order is reversed:

class A
{
  double m_nothing;
  int m_number;
};

Now we have to start with the double:

ffffdffffddd

Next, we have to add the int. As it turns out, the next free place is already correctly aligned for an int, therefore we can just append it:

ffffdffffdddiiii

Now for the use as base object, we are ready. As you can see, we only needed 12 bytes, therefore base size=12. Of course for the double to be correctly aligned, the object again has to start at an address which is a multiple of 8. Therefore we have base align=8.

However for the sue as complete object, we now find that the next address would be at position 12, which is not correctly aligned for the double member. Therefore we have to add padding bytes until we reach a correctly aligned address again:

ffffdffffdddiiii****

As you can see, now we need 16 bytes, thus size=16. We still have align=8 due to the double.

Note that the alignment requirement can dramatically affect the size of a class. Consider for example the following two types:

struct S1
{
  char c1;
  double d1;
  char c2;
  double d2;
  char c3;
};

struct S2
{
  double d1;
  double d2;
  char c1;
  char c2;
  char c3;
};

While both contain the same members, S1 will with the sizes and alignments above have a total (non-base) size of 40, while the total size of S2 will be just 24. Indeed, the objects of type S1 will, as complete object, look like

c*******ffffdffffdddc*******ffffdffffdddc*******

while those of type S2 will look like

ffffdffffdffffdffffdffffddccc*****

So the bottom line is that members with the highest alignment requirement should always come first.

Also note that sizeof returns the size of complete objects, that is, what the class hierarchy dump calls size.

查看更多
登录 后发表回答