C++;对象内存布局 我试图理解C++在多继承中的对象布局。 为此,我有两个超类A、B和一个子类C。 当我尝试倾倒它时,我期望看到的是: vfptr | A的字段| vfptr | B的字段| C的字段
我得到了这个模型,但是有一些我不明白的零。 这是我正在尝试的代码C++;对象内存布局 我试图理解C++在多继承中的对象布局。 为此,我有两个超类A、B和一个子类C。 当我尝试倾倒它时,我期望看到的是: vfptr | A的字段| vfptr | B的字段| C的字段,c++,object-layout,C++,Object Layout,我得到了这个模型,但是有一些我不明白的零。 这是我正在尝试的代码 #include <iostream> using namespace std; class A{ public: int a; A(){ a = 5; } virtual void foo(){ } }; class B{ public: int b; B(){ b
#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;
}
中间的零是什么意思?
提前谢谢 在不了解平台和编译器的情况下很难判断,但这可能是一个对齐问题。实际上,编译器可能会尝试沿8字节边界对齐类数据,并使用零作为填充
没有上面的细节,这只是猜测。这取决于您的编译器。使用叮当-500,我得到:
191787296
1
20
0
191787328
1
10
15
1785512560
我确信也有GDB方法,但如果我在类对象的地址使用LLDB转储指针大小的单词,我会得到:
0x7fff5fbff9d0: 0x0000000100002120 vtable for C + 16
0x7fff5fbff9d8: 0x0000000000000014
0x7fff5fbff9e0: 0x0000000100002140 vtable for C + 48
0x7fff5fbff9e8: 0x0000000f0000000a
这种布局似乎很合理,对吗?正是你所期望的。
这在程序中没有在调试器中显示得那么干净的原因是您正在转储int大小的单词。在64位系统上,sizeof(int)==4,但sizeof(void*)==8
因此,可以看到指针被分成(int,int)对。在Linux上,您的指针没有任何位设置超过low 32,而在OSX上,我的指针是这样设置的-因此,0与1之间存在差异的原因是这在很大程度上取决于体系结构和编译器。。。对于您来说,指针的大小可能不是整数的大小。。。您使用的是什么体系结构/编译器?如果您使用的是64位系统,那么:
- 第一个零是第一个
的4个最高有效字节vfptr
- 第二个零是填充,因此第二个
将与8字节地址对齐vfptr
- 第三个零是第二个
的4个最高有效字节vfptr
您可以检查sizeof(void*)==8,以断言这一点。这完全取决于您的编译器、系统和比特数 虚拟表指针的大小将与指针相同。这取决于您是将文件编译为32位还是64位。指针也将在其大小的多个地址上对齐(就像任何类型的指针一样)。这可能就是为什么在
20
之后出现0填充
这些整数的大小与特定系统上的整数相同。这通常是32位的。请注意,如果您的计算机上不是这种情况,您将得到意外的结果,因为您正在使用指针算法将ptr增加sizeof(int)。如果您使用MVSC,您可以使用-d1reportAllClassLayout转储解决方案中所有类的所有内存布局,如下所示: cl-d1reportAllClassLayout main.cpp
希望它对您有所帮助编译器:g++(Ubuntu/Linaro 4.6.3-1ubuntu5)4.6.3。据我所知,0被用作一种分隔符?@Griwes:你是在LLVM svn上还是在发布的clang上?没有“C++的对象布局”之类的东西。有一个“你的编译器本周碰巧在你的平台上生成的对象布局”。
中间的零是什么意思?提前谢谢代码>对齐填充。这是编译器特有的@n、 最好是上周和下周相同的编译器为这个平台生成相同的布局。如果您希望编译器之间的交互最少,那么最好使用不同编译器为同一平台生成的相同布局。这取决于架构和平台,您应该将它们添加到问题中。例如,英特尔的windows/64和linux/32的布局将非常不同,并且很可能与Solaris中的sparc/64不同…@DavidRodríguez dribeas这确实很好,但这类布局无法保证。我刚刚检查过。。谢谢!
0x7fff5fbff9d0: 0x0000000100002120 vtable for C + 16
0x7fff5fbff9d8: 0x0000000000000014
0x7fff5fbff9e0: 0x0000000100002140 vtable for C + 48
0x7fff5fbff9e8: 0x0000000f0000000a