考虑以下示例:
#include <iostream>
int main()
{
struct A {};
struct B : A {};
struct C : A, B {};
std::cout << sizeof(A) << '\n'; // 1
std::cout << sizeof(B) << '\n'; // 1
std::cout << sizeof(C) << '\n'; // 2, because of a duplicate base
struct E : A {virtual ~E() {}};
struct F : A, B {virtual ~F() {}};
std::cout << sizeof(E) << '\n'; // 8, the base overlaps the vtable pointer
std::cout << sizeof(F) << '\n'; // 16, but why?
}
Run Code Online (Sandbox Code Playgroud)
在这里,您可以看到,struct E空的基类(大1字节)使用了与vtable指针相同的存储空间,这与预期的一样。
但是对于struct F具有重复的空基数的,则不会发生这种情况。是什么原因造成的?
我在GCC,Clang和MSVC上得到了相同的结果。上面的结果适用于x64,因此sizeof(void *) == 8。
有趣的是,对于struct G : A, B {void *ptr;};GCC和Clang,请执行EBO(大小为8),但不执行MSVC(大小为16)。
因为编译器在struct A后面添加了一个字节填充
F {vptr(8) + 0 来自 A 的成员 + 1 个填充(因为 A 为空)+0 来自 b} = 9 然后编译器添加 7 个字节填充以对齐结构的存储;
E {vptr(8) + A 的 0 个成员} = 8 不需要填充
来自微软
每个数据对象都有对齐要求。对于结构,要求的是其最大的成员。每个对象都分配一个偏移量,以便 offset %alignment-requirement == 0
https://learn.microsoft.com/en-us/cpp/c-language/storage-and-alignment-of-structs?view=vs-2019
编辑:
这是我的演示:
int main()
{
C c;
A* a = &c;
B* b = &c;
std::cout << sizeof(A) << " " << a << '\n';
std::cout << sizeof(B) << " " << b << '\n';
std::cout << sizeof(C) << " " << &c << '\n';
E e;
a = &e;
std::cout << sizeof(E) <<" " << &e << " " << a << '\n';
F f;
a = &f;
b = &f;
std::cout << sizeof(F) << " " << &f << " " << a << " " << b << '\n';
}
Run Code Online (Sandbox Code Playgroud)
输出:
1 0000007A45B7FBB4
1 0000007A45B7FBB5
1 0000007A45B7FBB4
8 0000007A45B7FC18 0000007A45B7FC20
16 0000007A45B7FC38 0000007A45B7FC40 0000007A45B7FC41
Run Code Online (Sandbox Code Playgroud)
正如你所看到的, a 和 b 永远不会相互重叠,并且在多重继承上 vptr 每个都有自己的指针值
VC2019 x64 build 编译的注释
| 归档时间: |
|
| 查看次数: |
142 次 |
| 最近记录: |