为什么 类 带有虚函数的对齐方式与 类 不带虚函数的对齐方式不同?
Why are classes with virtual functions aligned differently than classes without?
受此启发 cppcon talk by Richard Powell 我创建了以下代码片段来愚弄:
#include <iostream>
using std::cout;
using std::endl;
struct erdos
{
void who()
{
cout << "erdos" << endl;
}
float f1;
float f2;
};
struct fermat : public erdos
{
float f3;
};
struct fermat2 : public fermat
{
float f4;
};
struct fermat3 : public fermat2
{
float f5;
};
int main(void)
{
erdos e;
cout << "sizeof(e)" << sizeof(e) << endl;
fermat f;
cout << "sizeof(f)" << sizeof(f) << endl;
fermat2 f2;
cout << "sizeof(f2)" << sizeof(f2) << endl;
fermat3 f3;
cout << "sizeof(f3)" << sizeof(f3) << endl;
cout << "sizeof(void*)" << sizeof(void*) << endl;
cout << "sizeof(float)" << sizeof(float) << endl;
return 0;
}
这将打印:
sizeof(e)8
sizeof(f)12
sizeof(f2)16
sizeof(f3)20
sizeof(void*)8
sizeof(float)4
将 virtual
添加到 who()
之后,我得到了这个
sizeof(e)16
sizeof(f)24
sizeof(f2)24
sizeof(f3)32
sizeof(void*)8
sizeof(float)4
现在,将 void*
的大小添加到结构中很简单,但为什么在虚拟情况下而不是在非虚拟情况下会有这种填充(理查德在他的演讲中也提到了这一点)?
sizeof(e)16 - 8 = 8
sizeof(f)24 - 8 = 16 but is in fact 12 (padding 4)
sizeof(f2)24 - 8 = 16 matches
sizeof(f3)32 - 8 = 24 but is in fact 20 (padding 4)
我已经在 Ubuntu 14.04 64 位
上使用 gcc 5.3.0 和 clang 3.7.1 对其进行了测试
sizeof(void*)8
嗯,这就是你的答案。
假设您的实现只需要一个指针来处理虚拟查找,这就是对齐的原因。在 64 位编译中,指针需要 64 位的 space(这就是我们称之为“64 位”的原因)。但是也需要64位alignment.
因此,任何在64位编译中存储指针的数据结构也必须是64位对齐的。对象的对齐必须是 8 字节对齐的,并且大小必须填充到 8 字节(出于数组索引的原因)。如果将 float
成员之一设为指针,您会看到相同的结果。
受此启发 cppcon talk by Richard Powell 我创建了以下代码片段来愚弄:
#include <iostream>
using std::cout;
using std::endl;
struct erdos
{
void who()
{
cout << "erdos" << endl;
}
float f1;
float f2;
};
struct fermat : public erdos
{
float f3;
};
struct fermat2 : public fermat
{
float f4;
};
struct fermat3 : public fermat2
{
float f5;
};
int main(void)
{
erdos e;
cout << "sizeof(e)" << sizeof(e) << endl;
fermat f;
cout << "sizeof(f)" << sizeof(f) << endl;
fermat2 f2;
cout << "sizeof(f2)" << sizeof(f2) << endl;
fermat3 f3;
cout << "sizeof(f3)" << sizeof(f3) << endl;
cout << "sizeof(void*)" << sizeof(void*) << endl;
cout << "sizeof(float)" << sizeof(float) << endl;
return 0;
}
这将打印:
sizeof(e)8
sizeof(f)12
sizeof(f2)16
sizeof(f3)20
sizeof(void*)8
sizeof(float)4
将 virtual
添加到 who()
之后,我得到了这个
sizeof(e)16
sizeof(f)24
sizeof(f2)24
sizeof(f3)32
sizeof(void*)8
sizeof(float)4
现在,将 void*
的大小添加到结构中很简单,但为什么在虚拟情况下而不是在非虚拟情况下会有这种填充(理查德在他的演讲中也提到了这一点)?
sizeof(e)16 - 8 = 8
sizeof(f)24 - 8 = 16 but is in fact 12 (padding 4)
sizeof(f2)24 - 8 = 16 matches
sizeof(f3)32 - 8 = 24 but is in fact 20 (padding 4)
我已经在 Ubuntu 14.04 64 位
上使用 gcc 5.3.0 和 clang 3.7.1 对其进行了测试sizeof(void*)8
嗯,这就是你的答案。
假设您的实现只需要一个指针来处理虚拟查找,这就是对齐的原因。在 64 位编译中,指针需要 64 位的 space(这就是我们称之为“64 位”的原因)。但是也需要64位alignment.
因此,任何在64位编译中存储指针的数据结构也必须是64位对齐的。对象的对齐必须是 8 字节对齐的,并且大小必须填充到 8 字节(出于数组索引的原因)。如果将 float
成员之一设为指针,您会看到相同的结果。