C++中类和结构体的空间大小如何分配

C++中类和结构体的空间大小分配有以下几个原则:

•  类和结构体的成员变量在内存中是按照声明的顺序依次存放的,但是可能会有一些空洞(padding)出现,以满足对齐要求。

•  对齐要求是指每个成员变量的起始地址要能够被其自身类型所占字节数的整数倍整除,如果不满足则需要在前面补充一些空字节。

•  对齐要求的目的是为了提高内存访问效率,不同的编译器和目标平台可能有不同的默认对齐值,一般是4字节或8字节,也可以通过#pragma pack指令来修改。

•  类和结构体本身也要满足对齐要求,即整个类或结构体的大小要能够被其最大成员变量所占字节数的整数倍整除,如果不满足则需要在末尾补充一些空字节。

•  类和结构体中的成员函数(包括构造函数、析构函数、静态函数、虚函数等)不占用对象的内存空间,而是存放在代码区,因此不影响类或结构体的大小。

•  类和结构体中的静态成员变量也不占用对象的内存空间,而是存放在静态区,因此不影响类或结构体的大小。

•  类和结构体中如果有虚函数,则会额外增加一个指向虚函数表(vtable)的指针(vptr),该指针占用4字节或8字节(取决于目标平台),并且通常放在对象的首地址处。

举例说明:

//定义一个结构体
struct A {               
    char a; //1字节
    int b; //4字节
    short c; //2字节
    double d; //8字节
};

//结构体A中,按照声明顺序依次存放成员变量,但是需要满足对齐要求:
//a占用第0单元,b需要从第4单元开始(因为4能被4整除),所以第1、2、3单元为空洞;
//b占用第4、5、6、7单元,c需要从第8单元开始(因为8能被2整除),所以没有空洞;
//c占用第8、9单元,d需要从第16单元开始(因为16能被8整除),所以第10、11、12、13、14、15单元为空洞;
//d占用第16、17、18、19、20、21、22、23单元,没有更多成员变量了;
//结构体A本身也需要满足对齐要求,即其大小要能被其最大成员变量d所占字节数8的整数倍整除;
//由于24能被8整除,所以不需要在末尾补充空字节;
//因此,结构体A的大小为24字节。

//定义一个类
class B {
    public:
        B() {} //构造函数
        ~B() {} //析构函数

        void f1() {} //普通成员函数
        static void f2() {} //静态成员函数
        virtual void f3() {} //虚函数

    private:
        char e; //1字节
        int f; //4字节
        short g; //2字节
        double h; //8字节
        static int i; //静态成员变量
};

//计算结构体A和类B的大小
int main() {
    cout << sizeof(A) << endl; //输出24
    cout << sizeof(B) << endl; //输出32(假设目标平台为64位)
    return 0;
}


//类B中,按照声明顺序依次存放成员变量,但是需要满足对齐要求:
//由于类B中有虚函数,所以会增加一个指向虚函数表的指针vptr,该指针通常放在对象的首地址处;
//假设目标平台为64位,那么vptr占用8字节,从第0单元开始,占用第0、1、2、3、4、5、6、7单元;
//e占用第8单元,f需要从第12单元开始(因为12能被4整除),所以第9、10、11单元为空洞;
//f占用第12、13、14、15单元,g需要从第16单元开始(因为16能被2整除),所以没有空洞;
//g占用第16、17单元,h需要从第24单元开始(因为24能被8整除),所以第18、19、20、21、22、23单元为空洞;
//h占用第24、25、26、27、28、29、30、31单元,没有更多成员变量了;
//类B本身也需要满足对齐要求,即其大小要能被其最大成员变量h所占字节数8的整数倍整除;
//由于32能被8整除,所以不需要在末尾补充空字节;
//因此,类B的大小为32字节。

//类B中的构造函数、析构函数、普通成员函数、静态成员函数和虚函数都不占用对象的内存空间,而是存放在代码区;
//类B中的静态成员变量i也不占用对象的内存空间,而是存放在静态区;
//这些都不影响类B的大小。
 

c++类中的大小与成员属性以及成员函数的关系?

一般来说,类中的成员属性(也就是数据成员)会占用对象的内存空间,而成员函数(也就是方法)则不会。这是因为成员属性是每个对象独有的,它们的值可能不同,所以需要为每个对象分配内存来存储它们。而成员函数是所有对象共享的,它们的代码只需要在内存中存储一份,然后通过指针来调用即可。

但是,这里有一些特殊情况需要注意:

•  如果类中有静态数据成员,那么它不会占用对象的内存空间,而是在全局数据区分配内存,所有对象共享同一个静态数据成员。

•  如果类中有虚函数,那么每个对象会多占用一个指针的大小的内存空间,用来存储虚函数表的地址。虚函数表是一个包含了该类所有虚函数地址的数组,它在程序运行时动态绑定虚函数的调用。

•  如果类中有继承或多态的关系,那么类的大小还要考虑基类和派生类之间的内存布局和对齐方式,这可能会导致一些额外的填充字节产生。

因此,如果想计算一个类的大小,需要知道它的数据成员的类型和数量,以及它是否有静态数据成员、虚函数、继承或多态等特性。然后你还需要根据编译器和平台的不同,确定它们的对齐规则和字节序。

注:空类的大小为1字节。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
定义结构体分配内存是在C语言中进行内存管理的常见操作。在C语言中,我们可以使用关键字"struct"来定义自己的结构体型,并使用函数malloc()来动态分配内存空间。 首先,我们可以使用如下的语法来定义一个结构体型: ``` struct Person { char name[20]; int age; float height; }; ``` 以上代码定义了一个名为"Person"的结构体型,包含了名字、年龄和身高三个字段。接下来,我们可以使用malloc()函数来给这个结构体分配内存空间并将其存储在一个指针变量中: ``` struct Person *personPtr; personPtr = (struct Person*)malloc(sizeof(struct Person)); ``` 在以上代码中,我们首先声明了一个名为"personPtr"的指针变量,它可以存储指向结构体型"Person"的指针。然后,使用malloc()函数来分配结构体型的大小相等的内存空间,并将返回的地址强制型转换为"Person"型的指针,并将其赋值给"personPtr"。 最后,我们可以通过指针变量来访问和操作结构体的字段: ``` strcpy(personPtr->name, "John"); personPtr->age = 25; personPtr->height = 1.75; ``` 在以上代码中,我们使用strcpy()函数将字符串"John"复制到结构体的"name"字段中,并直接通过指针变量访问和赋值结构体的其他字段。 最后,我们需要记得在使用完毕后,通过调用函数free()来释放动态分配的内存空间,以防止内存泄漏: ``` free(personPtr); ``` 以上是使用C语言定义结构体分配内存的基本操作。通过结构体,我们可以组织和存储不同型的数据,并通过动态内存分配来灵活管理内存空间,满足程序的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值