具有虚拟函数的类的大小 GCC/Xcode
谁能向我解释一下这是怎么回事?首先,我认为大多数程序员都知道具有虚函数的类有一个 vtbl,因此在其顶部有 4 个额外字节。据我所知,这是相当标准的。我已经对此进行了测试,并利用这一事实,从带有修补的 vtbls 的二进制文件进行就地加载。在过去的 6 个月里,我一直在 Xcode 中工作,最近才发现需要做一些就地加载的事情,所以我再次考虑修补 vtbls。为了确保我的理解是正确的,我编写了一个示例程序。这是:
class A
{
public:
virtual int getData()
{
return a;
}
virtual void print()
{
printf("hello\n");
}
int a;
};
class B : public A
{
public:
int getData()
{
return b;
}
int b;
};
class C : public B
{
public:
int getData()
{
return c;
}
void print()
{
printf("world\n");
}
int c;
};
class D
{
public:
int a;
int b;
};
int main (int argc, const char * argv[])
{
A* tA = new A();
tA->a = 1;
printf("A: %d\n", sizeof(A));
printf("A data: %d\n", tA->getData());
B* tB = new B();
tB->a = 2;
tB->b = 4;
printf("B: %d\n", sizeof(B));
printf("B data: %d\n", tB->getData());
C* tC = new C();
tC->c = 8;
printf("C: %d\n", sizeof(C));
printf("C data: %d\n", tC->getData());
A* aC = tC;
aC->print();
printf("D: %d\n", sizeof(D));
return 0;
}
我的预期输出是:
A: 8
A data: 1
B: 12
B data: 4 >
C: 16
C data: 8
world
D: 8
但是,我得到的输出是:
答:16
答数据:1
B:16
B 数据:4
C:24
C 数据:8
< Strong>world
D: 8
有人知道这里发生了什么吗?谢谢!
Can anyone explain to me what is going on here? First off, I think most programmers know that a class with a virtual function has a vtbl and thus has 4 extra bytes on the top of it. As far as I know, that's fairly standard. I've tested this and taken advantage of this fact before to do load in place from a binary file with patched vtbls. For the last 6 months, I've been working in Xcode and just recently came across the need to do some load in place stuff, so I was looking into patching vtbls again. Just to make sure my understanding was correct, I wrote a sample program. Here it is:
class A
{
public:
virtual int getData()
{
return a;
}
virtual void print()
{
printf("hello\n");
}
int a;
};
class B : public A
{
public:
int getData()
{
return b;
}
int b;
};
class C : public B
{
public:
int getData()
{
return c;
}
void print()
{
printf("world\n");
}
int c;
};
class D
{
public:
int a;
int b;
};
int main (int argc, const char * argv[])
{
A* tA = new A();
tA->a = 1;
printf("A: %d\n", sizeof(A));
printf("A data: %d\n", tA->getData());
B* tB = new B();
tB->a = 2;
tB->b = 4;
printf("B: %d\n", sizeof(B));
printf("B data: %d\n", tB->getData());
C* tC = new C();
tC->c = 8;
printf("C: %d\n", sizeof(C));
printf("C data: %d\n", tC->getData());
A* aC = tC;
aC->print();
printf("D: %d\n", sizeof(D));
return 0;
}
My expected output was:
A: 8
A data: 1
B: 12
B data: 4
C: 16
C data: 8
world
D: 8
However, the output I'm getting is:
A: 16
A data: 1
B: 16
B data: 4
C: 24
C data: 8
world
D: 8
Anybody have any idea what's going on here? Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
类 A 到 C 的实例包含 vptr,即指向动态类型的虚函数表的指针。该指针在 64 位机器上占用 8 个字节(在 32 位机器上占用 4 个字节)。每个int成员占用4个字节。
sizeof(Class) 的最小值是所有成员的 sizeof(member) 之和。如果是这样,那么
但是,这只是最小尺寸。编译器通常会将此大小增加到 sizeof(void*) 的倍数,这里是 8 个字节。这个过程称为对齐。这可能看起来浪费了内存,但性能增益抵消了这一点:CPU 读取对齐数据的速度比读取未对齐数据的速度快得多。
顺便说一下,如果您使用的是 32 位计算机,您的预期结果将是正确的。指针(尤其是 vptr)的宽度为 4 字节,对齐也是 4 字节的倍数。由于相关类的所有数据成员都是 4 字节大,因此对齐不会执行任何操作。
Instances of classes A through C contain a vptr, a pointer to the virtual function table for the dynamic type. This pointer occupies 8 bytes on your 64-bit machine (or 4 bytes on a 32-bit machine). Each int member takes up 4 bytes.
The minimum value of sizeof(Class) is the sum of sizeof(member) for all members. If it were like that, then
However, this is only the minimum size. Compilers usually increase this size to a multiple of sizeof(void*), which is 8 bytes here. This process is called aligning. It may look like this wastes memory, but this is outweighed by a performance gain: The CPU can read aligned data much faster than non-aligned data.
By the way, your expected result would have been correct if you were on a 32-bit machine. Pointers (esp. vptr) are 4 bytes wide there, and alignment is also to multiples of 4 bytes. Since all data members of the classes in question are 4 bytes big then, alignment wouldn't do anything there.