具有虚拟函数GCC / Xcode的类的大小 [英] Size of classes with virtual functions GCC/Xcode

查看:172
本文介绍了具有虚拟函数GCC / Xcode的类的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

任何人都可以向我解释这里发生了什么?首先,我认为大多数程序员知道一个带有虚函数的类有一个vtbl,因此在它的顶部有4个额外的字节。据我所知,这是相当标准。我测试了这个,并利用这个事实,然后从一个二进制文件加载到适当的vtbls。在过去的6个月中,我一直在Xcode工作,最近遇到了需要做一些负载在原地的东西,所以我正在研究修补vtbls。为了确保我的理解是正确的,我写了一个示例程序。这是:

  class A 
{
public:
virtual int getData
{
return a;
}

virtual void print()
{
printf(hello\\\
);
}
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\\\
);
}
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 \\\
,sizeof(A));
printf(A data:%d\\\
,tA-> getData());

B * tB = new B();
tB-> a = 2;
tB-> b = 4;

printf(B:%d \\\
,sizeof(B));
printf(B data:%d\\\
,tB-> getData());

C * tC = new C();
tC-> c = 8;

printf(C:%d \\\
,sizeof(C));
printf(C data:%d\\\
,tC-> getData());

A * aC = tC;
aC-> print();

printf(D:%d \\\
,sizeof(D));

return 0;
}



我的预期输出为:



答:8



A $ b

B:12 B:12



b $ b

C:16



C数据:8

世界

$ b

但是,我得到的输出是:



A:16



A数据:1



B:16 b $ b

B数据:4



C:24

C数据:8



世界 b $ b

D:8



任何人都知道这里发生了什么?谢谢!

解决方案

类A到C的实例包含一个vptr,一个指向动态类型的虚函数表的指针。此指针在64位机器上占用8个字节(或32位机器上的4个字节)。每个int成员占用4个字节。



sizeof(Class)的最小值是所有成员的sizeof(成员)的总和。如果是这样,那么

  sizeof(A)= 8(vptr)+ 4(int a)= 12 
sizeof(B)= 8(vptr)+ 4(int a)+ 4(int b)= 16
sizeof(C)= 8(vptr) + 4(int c)= 20
sizeof(D)= 4(int a)+ 4(int b)= 8

但是,这只是最小大小。编译器通常将此大小增加到sizeof(void *)的倍数,这是8个字节。这个过程称为对齐。它可能看起来像这样浪费内存,但是这超过了性能增益:CPU可以比非对齐数据更快地读取对齐的数据。



顺便说一句,你的预期结果将是正确的,如果你在一个32位机器。指针(esp。vptr)在那里有4个字节宽,并且对齐也是4个字节的倍数。因为所有类的所有数据成员都是4字节大,那么对齐方式将不会做任何事情。


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!

解决方案

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

sizeof(A) = 8 (vptr) + 4 (int a) = 12
sizeof(B) = 8 (vptr) + 4 (int a) + 4 (int b) = 16
sizeof(C) = 8 (vptr) + 4 (int a) + 4 (int b) + 4 (int c) = 20
sizeof(D) = 4 (int a) + 4 (int b) = 8

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.

这篇关于具有虚拟函数GCC / Xcode的类的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆