通过clang了解C++对象的内存布局

内存布局示例
class Base {
public:
    int method(int p);
protected:
    int foo;
private:
	int pbfoo;

};

struct Point {
  double cx, cy;
};

class Derived : public Base {
public:
  int method(int p);
protected:
  int bar, baz;
  Point a_point;
  char c;
};

int main(int argc, char** argv) {
  return sizeof(Derived);
}

要查看布局,请运行clang -cc1 -fdump-record-layouts myfile.cpp。它将为每个定义的类和结构生成一个单独的报告,但最有趣的一个是Derived类:

*** Dumping AST Record Layout
         0 | class Base
         0 |   int foo
         4 |   int pbfoo
             | [sizeof=8, dsize=8, align=4,
             |  nvsize=8, nvalign=4]

*** Dumping AST Record Layout
         0 | struct Point
         0 |   double cx
         8 |   double cy
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class Derived
         0 |   class Base (base)
         0 |     int foo
         4 |     int pbfoo
         8 |   int bar
      12 |   int baz
      16 |   struct Point a_point
      16 |     double cx
      24 |     double cy
      32 |   char c
             | [sizeof=40, dsize=33, align=8,
             |  nvsize=33, nvalign=8]
基类包含virtual函数
class Base {
public:
    int method(int p);
    virtual int vbfunc();
protected:
    int foo;
private:
	int pbfoo;

};

struct Point {
  double cx, cy;
};

class Derived : public Base {
public:
  int method(int p);
protected:
  int bar, baz;
  Point a_point;
  char c;
};

int main(int argc, char** argv) {
  return sizeof(Derived);
}

输出:

*** Dumping AST Record Layout
         0 | class Base
         0 |   (Base vtable pointer)
         8 |   int foo
      12 |   int pbfoo
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | struct Point
         0 |   double cx
         8 |   double cy
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class Derived
         0 |   class Base (primary base)
         0 |     (Base vtable pointer)
         8 |     int foo
      12 |     int pbfoo
      16 |   int bar
      20 |   int baz
      24 |   struct Point a_point
      24 |     double cx
      32 |     double cy
      40 |   char c
             | [sizeof=48, dsize=41, align=8,
             |  nvsize=41, nvalign=8]
派生类包含virtual函数
class Base {
public:
    int method(int p);
    int vbfunc();
protected:
    int foo;
private:
	int pbfoo;

};

struct Point {
  double cx, cy;
};

class Derived : public Base {
public:
  int method(int p);
  virtual int vbfunc();
  virtual int vdfunc();
protected:
  int bar, baz;
  Point a_point;
  char c;
};

int main(int argc, char** argv) {
  return sizeof(Derived);
}

输出:

*** Dumping AST Record Layout
         0 | class Base
         0 |   int foo
         4 |   int pbfoo
             | [sizeof=8, dsize=8, align=4,
             |  nvsize=8, nvalign=4]

*** Dumping AST Record Layout
         0 | struct Point
         0 |   double cx
         8 |   double cy
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class Derived
         0 |   (Derived vtable pointer)
         8 |   class Base (base)
         8 |     int foo
      12 |     int pbfoo
      16 |   int bar
      20 |   int baz
      24 |   struct Point a_point
      24 |     double cx
      32 |     double cy
      40 |   char c
             | [sizeof=48, dsize=41, align=8,
             |  nvsize=41, nvalign=8]
基类和派生类都包含virtual函数
class Base {
public:
    int method(int p);
    virtual int vbfunc();
protected:
    int foo;
private:
	int pbfoo;

};

struct Point {
  double cx, cy;
};

class Derived : public Base {
public:
  int method(int p);
  virtual int vbfunc();
  virtual int vdfunc();
protected:
  int bar, baz;
  Point a_point;
  char c;
};

int main(int argc, char** argv) {
  return sizeof(Derived);
}

输出:

*** Dumping AST Record Layout
         0 | class Base
         0 |   (Base vtable pointer)
         8 |   int foo
      12 |   int pbfoo
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | struct Point
         0 |   double cx
         8 |   double cy
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class Derived
         0 |   class Base (primary base)
         0 |     (Base vtable pointer)
         8 |     int foo
      12 |     int pbfoo
      16 |   int bar
      20 |   int baz
      24 |   struct Point a_point
      24 |     double cx
      32 |     double cy
      40 |   char c
             | [sizeof=48, dsize=41, align=8,
             |  nvsize=41, nvalign=8]
virtual继承
class Base {
public:
    int method(int p);
    virtual int vbfunc();
protected:
    int foo;
private:
	int pbfoo;

};

class VBase {
public:
    int method(int p);
    virtual int vbfunc();
protected:
    int foo;
private:
  int pbfoo;

};

struct Point {
  double cx, cy;
};

class Derived : public virtual VBase, public Base {
public:
  int method(int p);
  virtual int vbfunc();
  virtual int vdfunc();
protected:
  int bar, baz;
  Point a_point;
  char c;
};

int main(int argc, char** argv) {
  return sizeof(Derived);
}

输出:

*** Dumping AST Record Layout
         0 | class VBase
         0 |   (VBase vtable pointer)
         8 |   int foo
      12 |   int pbfoo
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class Base
         0 |   (Base vtable pointer)
         8 |   int foo
      12 |   int pbfoo
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | struct Point
         0 |   double cx
         8 |   double cy
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class Derived
         0 |   class Base (primary base)
         0 |     (Base vtable pointer)
         8 |     int foo
      12 |     int pbfoo
      16 |   int bar
      20 |   int baz
      24 |   struct Point a_point
      24 |     double cx
      32 |     double cy
      40 |   char c
      48 |   class VBase (virtual base)
      48 |     (VBase vtable pointer)
      56 |     int foo
      60 |     int pbfoo
             | [sizeof=64, dsize=64, align=8,
             |  nvsize=41, nvalign=8]
virtaul继承2
class VBase {
public:
    int method(int p);
    virtual int vbfunc();
protected:
    int foo;
private:
  int pbfoo;

};

class Base : public virtual VBase {
public:
    int method(int p);
    virtual int vbfunc();
protected:
    int foo;
private:
  int pbfoo;

};


struct Point {
  double cx, cy;
};

class Derived : public virtual VBase, public Base {
public:
  int method(int p);
  virtual int vbfunc();
  virtual int vdfunc();
protected:
  int bar, baz;
  Point a_point;
  char c;
};

int main(int argc, char** argv) {
  return sizeof(Derived);
}

输出:

*** Dumping AST Record Layout
         0 | class VBase
         0 |   (VBase vtable pointer)
         8 |   int foo
      12 |   int pbfoo
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class Base
         0 |   (Base vtable pointer)
         8 |   int foo
      12 |   int pbfoo
      16 |   class VBase (virtual base)
      16 |     (VBase vtable pointer)
      24 |     int foo
      28 |     int pbfoo
             | [sizeof=32, dsize=32, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | struct Point
         0 |   double cx
         8 |   double cy
             | [sizeof=16, dsize=16, align=8,
             |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class Derived
         0 |   class Base (primary base)
         0 |     (Base vtable pointer)
         8 |     int foo
      12 |     int pbfoo
      16 |   int bar
      20 |   int baz
      24 |   struct Point a_point
      24 |     double cx
      32 |     double cy
      40 |   char c
      48 |   class VBase (virtual base)
      48 |     (VBase vtable pointer)
      56 |     int foo
      60 |     int pbfoo
             | [sizeof=64, dsize=64, align=8,
             |  nvsize=41, nvalign=8]