扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
不同的数据在内存中有不同的保存时机、保存位置。在执行程序时,总内存会被分为多个段,称为文本,未初始化的全局、初始化的全局、栈和堆段。将整个程序加载到文本段中,并在堆栈存储器中选择存储器到变量。
成都创新互联-专业网站定制、快速模板网站建设、高性价比源汇网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式源汇网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖源汇地区。费用合理售后完善,10多年实体公司更值得信赖。High Addresses --->.----------------------.
| Environment |
|----------------------|
| | Functions and variable are declared
| STACK | on the stack.
base pointer ->| - - - - - - - - - - -|
| | |
| v |
: :
. . The stack grows down into unused space
. Empty . while the heap grows up.
. .
. . (other memory maps do occur here, such
. . as dynamic libraries, and different memory
: : allocate)
| ^ |
| | |
brk point ->| - - - - - - - - - - -| Dynamic memory is declared on the heap
| HEAP |
| |
|----------------------|
| BSS | Uninitialized data (BSS)
|----------------------|
| Data | Initialized data (DS)
|----------------------|
| Text | Binary code
Low Addresses ---->'----------------------'
栈(STACK)此段包含所有未初始化的全局和静态变量,所有变量都由零或者空指针初始化。程序加载器在加载程序时为BSS节分配内存。
初始化的数据块(DS)此段包含显式初始化的全局变量和静态变量,大小由程序源代码中值的大小决定,在运行时不会更改。它具有读写权限,因此可以在运行时更改此段的变量值。
代码段(TEXT)该段是一个只读段,包含已编译程序的二进制文件。该段是可共享的,因此对于文本编辑器等频繁执行的程序,内存中只需要一个副本
C++单继承下内存布局分析#includeclass A
{public:
int a;
A() : a(0x1) {}
virtual void foo() {std::cout<< "A::foo()"<< std::endl; }
void bar() {std::cout<< "A::bar()"<< std::endl; }
};
class B : public A
{public:
int b;
B() : A(), b(0x2) {}
void foo() {std::cout<< "B::foo()"<< std::endl; }
};
class C : public B
{public:
int c;
C() : B(), c(0x3) {}
void foo() {std::cout<< "C::foo()"<< std::endl; }
};
int main(int argc, char **argv)
{A a;
B b;
C c;
B *p = &c;
p->foo();
std::cout<< sizeof(int)<< " "<< sizeof(int *)<< std::endl;
return 0;
}
g++ main.cpp -o main -std=c++14 -g
gdb查看
(gdb) b 29
Breakpoint 1 at 0x120b: file main.cpp, line 29.
(gdb) r
Breakpoint 1, main (argc=1, argv=0x7fffffffdd48) at main.cpp:29
29 A a;
(gdb) n
30 B b;
(gdb) set print pretty on
(gdb) set print vtbl on
(gdb) p a
$1 = {_vptr.A = 0x555555557d38,
a = 1
}
(gdb) p/a &a
$2 = 0x7fffffffdbf0
(gdb) p/a &a.a
$3 = 0x7fffffffdbf8
(gdb) p sizeof(a)
$4 = 16
(gdb) x/2xg &a
0x7fffffffdbf0: 0x0000555555557d38 0x00007fff00000001
(gdb) info vtbl a
vtable for 'A' @ 0x555555557d38 (subobject @ 0x7fffffffdbf0):
[0]: 0x555555555344
gdb查看
(gdb) n
31 C c;
(gdb) p b
$6 = {= {_vptr.A = 0x555555557d20,
a = 1
},
members of B:
b = 2
}
(gdb) p sizeof(b)
$7 = 16
(gdb) n
32 B *p = &c;
(gdb) p c
$8 = {= {= { _vptr.A = 0x555555557d08,
a = 1
},
members of B:
b = 2
},
members of C:
c = 3
}
(gdb) p sizeof(c)
$9 = 24
(gdb) info vtbl b
vtable for 'B' @ 0x555555557d20 (subobject @ 0x7fffffffdc00):
[0]: 0x5555555553ba(gdb) info vtbl c
vtable for 'C' @ 0x555555557d08 (subobject @ 0x7fffffffdc10):
[0]: 0x555555555430
如果class B中申明了新的虚函数(比如foo2),class B中依然只有一个虚函数表,只不过会把foo2加入到该表中。此时class A的虚函数表不会包含foo2。
C++多重继承下内存布局分析#includeclass A
{int a;
virtual void foo() {std::cout<< "A::foo()"<< std::endl; }
};
class B
{int b;
virtual void bar() {std::cout<< "B::bar()"<< std::endl; }
};
class C : public A, public B
{int c;
void foo() {std::cout<< "C::foo()"<< std::endl; }
void bar() {std::cout<< "C::bar()"<< std::endl; }
};
int main(int argc, char **argv)
{A a;
B b;
C c;
std::cout<< sizeof(int)<< " "<< sizeof(int *)<< std::endl;
return 0;
}
gdb查看
gdb main
(gdb) b 28
Breakpoint 1 at 0x122f: file main.cpp, line 28.
(gdb) set print pretty on
(gdb) set print vtbl on
(gdb) set print object on
(gdb) p a
No symbol "a" in current context.
(gdb) r
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main (argc=1, argv=0x7fffffffdd48) at main.cpp:28
28 std::cout<< sizeof(int)<< " "<< sizeof(int *)<< std::endl;
(gdb) p a
$1 = (A) {_vptr.A = 0x555555557d20,
a = -134528544
}
(gdb) p b
$2 = (B) {_vptr.B = 0x555555557d08,
b = -135408993
}
(gdb) p/a c
$3 = (C) {= {_vptr.A = 0x555555557cd0,
a = 0xfffffffff7eab60a
},
= {_vptr.B = 0x555555557cf0,
b = 0xfffffffff7fb3e88
},
members of C:
c = 0x7fff
--Typefor more, q to quit, c to continue without paging--
}
(gdb) p sizeof(c)
$4 = 32
(gdb) x/5ag &c
0x7fffffffdc00: 0x555555557cd0<_ZTV1C+16> 0x7ffff7eab60a<_ZNSt9basic_iosIwSt11char_traitsIwEE15_M_cache_localeERKSt6locale+90>0x7fffffffdc10: 0x555555557cf0<_ZTV1C+48> 0x7ffff7fb3e88<_ZSt5wclog+8>0x7fffffffdc20: 0x7ffff7fb3940
#includeclass A
{
int a;
virtual void foo() { std::cout<< "A::foo()"<< std::endl; }
};
class B : virtual public A
{
int b;
virtual void foo() { std::cout<< "B::foo()"<< std::endl; }
};
class C : virtual public A
{
int c;
void foo() { std::cout<< "C::foo()"<< std::endl; }
};
class D : public B, public C
{
int d;
virtual void foo() { std::cout<< "D::foo()"<< std::endl; }
};
int main(int argc, char **argv)
{
A a;
B b;
C c;
D d;
A *pa = &d;
B *pb = &d;
C *p c = &d;
std::cout<< sizeof(int)<< " "<< sizeof(int *)<< std::endl;
return 0;
}
gdb查看
gdb main
(gdb) b 37
Breakpoint 1 at 0x1247: file main.cpp, line 37.
(gdb) r
37 std::cout<< sizeof(int)<< " "<< sizeof(int *)<< std::endl;
(gdb) set print pretty on
(gdb) set print object on
(gdb) set print vtbl on
(gdb) p a
$1 = (A) {
_vptr.A = 0x555555557ce0,
a = 0
}
(gdb) p b
$2 = (B) {
= {
_vptr.A = 0x555555557cb8,
a = -238370304
},
members of B:
_vptr.B = 0x555555557c98,
b = 0
--Typefor more, q to quit, c to continue without paging--
}
(gdb) p c
$3 = (C) {
= {
_vptr.A = 0x555555557c68,
a = -134528544
},
members of C:
_vptr.C = 0x555555557c48,
c = -134529192
}
(gdb) p d
$4 = (D) {
= {
= {
_vptr.A = 0x555555557b70,
a = -134529400
},
members of B:
_vptr.B = 0x555555557b30,
b = -135408993
},= {
members of C:
_vptr.C = 0x555555557b50,
c = -135612918
},
members of D:
d = 32767
}
(gdb) p &d
$5 = (D *) 0x7fffffffdbf0
class A
{public:
int m_a;
int m_b;
static int m_c; // 声明
}
int A::m_c = 0; // 定义
#include#includeclass Base
{public:
int m_a;
int m_b;
};
class Derived : public Base
{public:
int m_i;
int m_j;
};
int main(int argc, char **argv)
{// 打印成员变量偏移值
printf("Base::m_a = %d\n", &Base::m_a);
printf("Base::m_b = %d\n", &Base::m_b);
printf("Derived::m_a = %d\n", &Derived::m_a);
printf("Derived::m_b = %d\n", &Derived::m_b);
printf("Derived::m_i = %d\n", &Derived::m_i);
printf("Derived::m_j = %d\n", &Derived::m_j);
Base b; // m_a | m_b
Derived d; // m_a | m_b | m_i | m_j
return 0;
}
#include#includeclass Base1
{
public:
int m_a;
char m_c1;
};
class Base2 : public Base1
{
public:
char m_c2;
};
class Base3 : public Base2
{
public:
char m_c3;
};
int main(int argc, char **argv)
{
Base1 b1; // 8byte: 4 | 1 | 3padding
Base2 b2; // 12byte: 4 | 1 | 3padding | 1 | 3padding
Base3 b3; // 12byte: 4 | 1 | 3padding | 1 | 1 | 2padding
printf("sizeof(Base1) = %d\n", sizeof(Base1));
printf("sizeof(Base2) = %d\n", sizeof(Base2));
printf("sizeof(Base3) = %d\n", sizeof(Base3));
// 打印成员变量偏移值
printf("Base3::m_a = %d\n", &Base3::m_a);
printf("Base3::m_c1 = %d\n", &Base3::m_c1);
printf("Base3::m_c2 = %d\n", &Base3::m_c2);
printf("Base3::m_c3 = %d\n", &Base3::m_c3);
return 0;
}
输出结果
sizeof(Base1) = 8
sizeof(Base2) = 12
sizeof(Base3) = 12
Base3::m_a = 0
Base3::m_c1 = 4
Base3::m_c2 = 8
Base3::m_c3 = 9
单类单继承虚函数下的数据成员布局
单个类带虚函数的数据成员布局类中引入虚函数时会有额外的成本付出:
class Base
{public:
int m_i;
int m_j;
Base() {}
~Base(){}
virtual void func() {}
};
//内存布局为
// vptr | m_i | m_j
单一继承下父类带虚函数的数据成员布局#include#includeclass Base
{
public:
int m_i;
Base() {}
~Base() {}
virtual void b_func() {}
};
class Derived : public Base
{
public:
int m_a;
int m_b;
Derived() {}
~Derived() {}
virtual void d_func() {}
};
int main(int argc, char **argv)
{
printf("sizeof(Base) = %d\n", sizeof(Base));
printf("sizeof(Derived) = %d\n", sizeof(Derived));
Base b;
Derived d;
printf("Base::m_i = %d\n", &Base::m_i);
printf("Derived::m_i = %d\n", &Derived::m_i);
printf("Derived::m_a = %d\n", &Derived::m_a);
printf("Derived::m_b = %d\n", &Derived::m_b);
return 0;
}
输出结果为
sizeof(Base) = 16
sizeof(Derived) = 24
Base::m_i = 8
Derived::m_i = 8
Derived::m_a = 12
Derived::m_b = 16
//内存布局为
//Base: vptr | m_i | padding4
//Derived: vptr | m_i | m_a | m_b | padding4
单一继承下父类不带虚函数的数据成员布局#include#includeclass Base
{public:
int m_i;
Base() {}
~Base() {}
};
class Derived : public Base
{public:
int m_a;
int m_b;
Derived() {}
~Derived() {}
virtual void d_func() {}
};
int main(int argc, char **argv)
{printf("sizeof(Base) = %d\n", sizeof(Base));
printf("sizeof(Derived) = %d\n", sizeof(Derived));
Derived d;
d.m_i = 1;
d.m_a = 2;
d.m_b = 3;
printf("Base::m_i = %d\n", &Base::m_i);
printf("Derived::m_i = %d\n", &Derived::m_i);
printf("Derived::m_a = %d\n", &Derived::m_a);
printf("Derived::m_b = %d\n", &Derived::m_b);
return 0;
}
gdb查看
gdb main
(gdb) set print pretty on
(gdb) set print object on
(gdb) set print vtbl on
(gdb) b 35
Breakpoint 1 at 0x123f: file main.cpp, line 35.
(gdb) r
sizeof(Base) = 4
sizeof(Derived) = 24
Breakpoint 1, main (argc=1, argv=0x7fffffffdd48) at main.cpp:35
35 printf("Base::m_i = %d\n", &Base::m_i);
(gdb) p/a &d
$1 = 0x7fffffffdc00
(gdb) x/10xw &d
0x7fffffffdc00: 0x55557d40 0x00005555 0x00000001 0x00000002
0x7fffffffdc10: 0x00000003 0x00007fff 0x342a4e00 0xa0066d24
0x7fffffffdc20: 0xf7fb3940 0x00007fff
(gdb) info vtbl d
vtable for 'Derived' @ 0x555555557d40 (subobject @ 0x7fffffffdc00):
[0]: 0x5555555553e4
从gdb调试信息可以看出
d的vptr为0x555555557d40 即从虚拟地址0x7fffffffdc00~0x7fffffffdc07
地址0x7fffffffdc08~0x7fffffffdc0b的值为0x00000001即d.m_i的值
地址0x7fffffffdc0c~0x7fffffffdc0f的值为0x00000002即d.m_a的值
地址0x7fffffffdc10~0x7fffffffdc13的值为0x00000003即d.m_b的值
由此可得d的内存布局为:vptr | m_i | m_a | m_b | padding4
#include#includeclass Base1
{public:
int m_b1;
Base1() {printf(" Base1::Base1() 的this指针是:%p\n", this); }
~Base1() {}
virtual void func_b1() {}
};
class Base2
{public:
int m_b2;
Base2() {printf(" Base2::Base2() 的this指针是:%p\n", this); }
~Base2() {}
virtual void func_b2() {}
};
class Derived : public Base1, public Base2
{public:
int m_a;
int m_b;
Derived()
{printf("Derived::Derived() 的this指针是:%p\n", this);
}
~Derived() {}
virtual void d_func() {}
};
int main(int argc, char **argv)
{printf("sizeof(Base1) = %d\n", sizeof(Base1));
printf("sizeof(Base2) = %d\n", sizeof(Base2));
printf("sizeof(Derived) = %d\n", sizeof(Derived));
Derived d;
d.m_b1 = 1;
d.m_b2 = 2;
d.m_a = 3;
d.m_b = 4;
printf("Base1::m_b1 = %d\n", &Base1::m_b1);
printf("Base2::m_b2 = %d\n", &Base2::m_b2);
printf("Derived::m_b1 = %d\n", &Derived::m_b1);
printf("Derived::m_b2 = %d\n", &Derived::m_b2);
printf("Derived::m_a = %d\n", &Derived::m_a);
printf("Derived::m_b = %d\n", &Derived::m_b);
return 0;
}
gdb查看
gdb main
(gdb) set print pretty on
(gdb) set print object on
(gdb) set print vtbl on
(gdb) b 51
Breakpoint 1 at 0x125f: file main.cpp, line 51.
(gdb) r
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
sizeof(Base1) = 16
sizeof(Base2) = 16
sizeof(Derived) = 40
Base1::Base1() 的this指针是:0x7fffffffdbf0
Base2::Base2() 的this指针是:0x7fffffffdc00
Derived::Derived() 的this指针是:0x7fffffffdbf0
Breakpoint 1, main (argc=1, argv=0x7fffffffdd48) at main.cpp:51
51 printf("Base1::m_b1 = %d\n", &Base1::m_b1);
(gdb) p d
$1 = (Derived) {= {_vptr.Base1 = 0x555555557cd0,
m_b1 = 1
},= {_vptr.Base2 = 0x555555557cf0,
m_b2 = 2
},
members of Derived:
m_a = 3,
m_b = 4
}
(gdb) x/10xw &d
0x7fffffffdbf0: 0x55557cd0 0x00005555 0x00000001 0x00007fff
0x7fffffffdc00: 0x55557cf0 0x00005555 0x00000002 0x00000003
0x7fffffffdc10: 0x00000004 0x00007fff
(gdb) info vtbl d
vtable for 'Derived' @ 0x555555557cd0 (subobject @ 0x7fffffffdbf0):
[0]: 0x55555555540c[1]: 0x555555555576vtable for 'Base2' @ 0x555555557cf0 (subobject @ 0x7fffffffdc00):
[0]: 0x555555555476
从gdb调试信息可以看出
Base1的虚函数指针vptr1和继承Derived的虚函数指针vptr同在0x7fffffffdbf0处,即继承类和多个基类的第一个类共用一个vptr
地址0x7fffffffdbf0~0x7fffffffdbf7的值为0x0000555555557cd0即_vptr.Base1
地址0x7fffffffdbf8~0x7fffffffdbfb的值为0x00000001即m_b1的值
地址0x7fffffffdbfc~0x7fffffffdbff的值为4字节的填充
地址0x7fffffffdc00~0x7fffffffdc07的值为0x0000555555557cf0即_vptr.Base2
地址0x7fffffffdc08~0x7fffffffdc0b的值为0x00000002即m_b2的值
地址0x7fffffffdc0c~0x7fffffffdc0f的值为0x00000003即m_a的值
地址0x7fffffffdc10~0x7fffffffdc13的值为0x00000004即m_b的值
由此可得d的内存布局为:_vptr.Base1 | m_b1 | 4padding |_vptr.Base2 | m_b2 | m_a | m_b | padding4
传统多重继承的问题:空间问题、效率问题、二义性问题
|-----------| |-----------|
| Base | | Base |
|-----------| |-----------|
| |
\|/ \|/
|----------| |----------|
| Derived1 | | Derived2 |
|----------| |----------|
| |
|---------------|
|
\|/
|----------|
| C |
|----------|
#include#includeclass Base
{public:
int m_b1;
};
class Derived1 : public Base
{public:
};
class Derived2 : public Base
{public:
};
class C : public Derived1, public Derived2
{};
int main(int argc, char **argv)
{printf("sizeof(Base) = %ld\n", sizeof(Base));
printf("sizeof(Derived1) = %ld\n", sizeof(Derived1));
printf("sizeof(Derived2) = %ld\n", sizeof(Derived2));
printf("sizeof(C) = %ld\n", sizeof(C));
C c; // c的内存布局为:m_b1 | m_b1
c.Derived1::m_b1 = 1;
c.Derived2::m_b1 = 1;
return 0;
}
虚基类初探虚基类表vbtable(virtual base table)
虚基类表指针vbptr(virtual base table pointer)
示例1
|-----------|
| Base |
|-----------|
|
---------------
virtual | | virtual
\|/ \|/
|----------| |----------|
| Derived1 | | Derived2 |
|----------| |----------|
#include#includeclass Base
{public:
int m_b;
};
class Derived1 : virtual public Base
{public:
int m_d1;
};
class Derived2 : virtual public Base
{public:
int m_d2;
};
int main(int argc, char **argv)
{printf("sizeof(Base) = %ld\n", sizeof(Base));
printf("sizeof(Derived1) = %ld\n", sizeof(Derived1));
Derived1 d1;
d1.m_b = 0x1111;
d1.m_d1 = 0x2222;
return 0;
}
gdb查看
gdb main
(gdb) b 31
Breakpoint 1 at 0x1230: file main.cpp, line 32.
(gdb) set print pretty on
(gdb) r
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
sizeof(Base) = 4
sizeof(Derived1) = 16
Breakpoint 1, main (argc=1, argv=0x7fffffffdd48) at main.cpp:32
32 return 0;
(gdb) p &d1
$1 = (Derived1 *) 0x7fffffffdc10
(gdb) p d1
$2 = { = {m_b = 4369
},
members of Derived1:
_vptr.Derived1 = 0x555555557d58,
m_d1 = 8738
}
(gdb) x/2xg 0x7fffffffdc10
0x7fffffffdc10: 0x0000555555557d58 0x0000111100002222
其中:
sizeof(Derived1) = 16, &d=0x7fffffffdc10
0x7fffffffdc10~0x7fffffffdc17内容为0x0000555555557d58即_vptr.Derived1
0x7fffffffdc18~0x7fffffffdc1b内容为00002222即d1.m_d1 = 0x2222;
0x7fffffffdc1c~0x7fffffffdc1f内容为00001111即d1.m_b = 0x1111;
由此可得d1的内存布局为: vptr | m_d1 | m_b(虚基类对象大小)
virtual虚继承之后,Derived1、Derived2会被编译器插入一个虚基类表指针
示例2
|-----------| |-----------|
| Base1 | | Base2 |
|-----------| |-----------|
virtual | | public
|---------------|
|
\|/
|----------|
| Derived1 |
|----------|
#include#includeclass Base1
{public:
int m_b1;
};
class Base2
{public:
int m_b2;
};
class Derived1 : virtual public Base1, public Base2
{public:
int m_d1;
};
int main(int argc, char **argv)
{printf("sizeof(Base1) = %ld\n", sizeof(Base1));
printf("sizeof(Base2) = %ld\n", sizeof(Base2));
printf("sizeof(Derived1) = %ld\n", sizeof(Derived1));
Derived1 d1;
d1.m_b1 = 0xb1;
d1.m_b2 = 0xb2;
d1.m_d1 = 0x2222;
return 0;
}
gdb查看
gdb main
(gdb) b 33
Breakpoint 1 at 0x1237: file main.cpp, line 33.
(gdb) set print pretty on
(gdb) r
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
sizeof(Base1) = 4
sizeof(Base2) = 4
sizeof(Derived1) = 24
Breakpoint 1, main (argc=1, argv=0x7fffffffdd48) at main.cpp:33
warning: Source file is more recent than executable.
33 return 0;
(gdb) p d1
$1 = {= {m_b1 = 177
},= {m_b2 = 178
},
members of Derived1:
_vptr.Derived1 = 0x555555557d38,
m_d1 = 8738
}
(gdb) p d1
$2 = {= {m_b1 = 177
},= {m_b2 = 178
},
members of Derived1:
_vptr.Derived1 = 0x555555557d38,
m_d1 = 8738
}
(gdb) p &d1
$3 = (Derived1 *) 0x7fffffffdc10
(gdb) x/6xw 0x7fffffffdc10
0x7fffffffdc10: 0x55557d38 0x00005555 0x000000b2 0x00002222
0x7fffffffdc20: 0x000000b1 0x00007fff
其中:
sizeof(Derived1) = 24, &d1=0x7fffffffdc10
0x7fffffffdc10~0x7fffffffdc17内容为0x0000555555557d38即_vptr.Derived1
0x7fffffffdc18~0x7fffffffdc1b内容为0x000000b2即d1.m_b2 = 0x000000b2;
0x7fffffffdc1c~0x7fffffffdc1f内容为0x00002222即d1.m_d1 = 0x2222;
0x7fffffffdc20~0x7fffffffdc23内容为0x000000b1即d1.m_b1 = 0x000000b1;
由此可得d1的内存布局为: vptr | m_b2 | m_d1 | m_b1(虚基类对象大小) | padding4 |
|-----------|
| Base |
|-----------|
|
---------------
virtual | | virtual
\|/ \|/
|----------| |----------|
| Derived1 | | Derived2 |
|----------| |----------|
| |
|---------------|
|
\|/
|----------|
| C |
|----------|
#include#includeclass Base
{public:
int m_b1;
};
class Derived1 : virtual public Base
{public:
int m_d1;
};
class Derived2 : virtual public Base
{public:
int m_d2;
};
class C : public Derived1, public Derived2
{public:
int m_c;
};
int main(int argc, char **argv)
{printf("sizeof(Base) = %ld\n", sizeof(Base));
printf("sizeof(Derived1) = %ld\n", sizeof(Derived1));
printf("sizeof(Derived2) = %ld\n", sizeof(Derived2));
printf("sizeof(C) = %ld\n", sizeof(C));
C c;// c的内存布局为:vbptr1(from Derived1) | m_d1 | vbptr2(from Derived2) | m_d2 | m_c | m_b1(虚基类对象)
c.m_b1 = 0xb1;
c.m_d1 = 0xd1;
c.m_d2 = 0xd2;
c.m_c = 0xc;
return 0;
}
gdb查看
gdb main
(gdb) b 41
Breakpoint 1 at 0x1257: file main.cpp, line 41.
(gdb) r
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
sizeof(Base) = 4
sizeof(Derived1) = 16
sizeof(Derived2) = 16
sizeof(C) = 40
Breakpoint 1, main (argc=1, argv=0x7fffffffdd48) at main.cpp:41
41 return 0;
(gdb) p &c
$1 = (C *) 0x7fffffffdc00
(gdb) set print pretty on
(gdb) p c
$3 = {= { = { m_b1 = 177
},
members of Derived1:
_vptr.Derived1 = 0x555555557c98,
m_d1 = 209
},= {members of Derived2:
_vptr.Derived2 = 0x555555557cb0,
m_d2 = 210
},
members of C:
m_c = 12
}
(gdb) x/10xw 0x7fffffffdc00
0x7fffffffdc00: 0x55557c98 0x00005555 0x000000d1 0x00007fff
0x7fffffffdc10: 0x55557cb0 0x00005555 0x000000d2 0x0000000c
0x7fffffffdc20: 0x000000b1 0x00007fff
其中:
sizeof© = 40, &c=0x7fffffffdc00
0x7fffffffdc00~0x7fffffffdc07内容为0x0000555555557c98即_vptr.Derived1 = 0x555555557c98,由于多继承派生类与第一个基类共用一个vptr,即c的vptr=0x555555557c98
0x7fffffffdc08~0x7fffffffdc0b内容为0x000000d1即c.m_d1 = 0x000000d1;
0x7fffffffdc10~0x7fffffffdc17内容为0x0000555555557cb0即_vptr.Derived2 = 0x555555557cb0;
0x7fffffffdc18~0x7fffffffdc1b内容为0x000000d2即c.m_d2 = 0xd2;
0x7fffffffdc1c~0x7fffffffdc1f内容为0x0000000c即c.m_c = 0xc;
0x7fffffffdc20~0x7fffffffdc23内容为0x000000b1即c.m_b1 = 0xb1;
由此可得c的内存布局为: vptr1 | m_d1 | padding4 | vptr2 | m_d2 | m_c | m_b1(虚基类对象大小) | padding4 |
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流