Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do compilers (e.g. gcc) deal with the memory layout of derived classes in this way?

Here is my cpp code.

#include <iostream>
using namespace std;

class A {
public:
    int val;
    char a;
};

class B: public A {
public:
    char b;
};

class C: public B {
public:
    char c;
};

int main()
{
    cout << sizeof(A) << endl;
    cout << sizeof(B) << endl;
    cout << sizeof(C) << endl;

    return 0;
}

The output of the program (in gcc) is:

8
12
12

This output confuses me a lot.

I know that the alignment may be the reason why sizeof(A) equals to 8. (sizeof(int) + sizeof(char) + 3 bytes padding)

And I also guess that the expansion of sizeof(B) (sizeof(B) == sizeof(A) + sizeof(char) + 3 bytes padding) is to avoid overlap when copy occurs. (is that right?)

But what I really don't know why sizeof(B) is equal to sizeof(C).

Thanks a lot.

like image 206
Wizmann Avatar asked May 24 '14 05:05

Wizmann


1 Answers

Both GCC and Clang follow the Itanium C++ ABI document, which specifies:

... implementations may freely allocate objects in the tail padding of any class which would not have been POD in C++98

class A is POD, so the compiler cannot put stuff into its padding. class B isn't POD, so the compiler is free to re-use the padding within the base class layout for members of derived objects. The basic idea here was that the C++ class layout should mirror the equivalent C struct layout for POD types, but there is no limitation for other classes. Because the meaning of "POD" has changed multiple times, they explicitly use the definition from C++98.

EDIT: About the rationale. POD-types are very simple classes that could be implemented as struct in C. For those types the layout should be identical to the layout a C compiler would create. In particular they want to allow C-tools like memcpy for A. If char b; were within the padding of A, memcpy would destroy it.

like image 197
pentadecagon Avatar answered Oct 31 '22 09:10

pentadecagon