zoukankan      html  css  js  c++  java
  • c++中类对象的内存对齐

    很多C++书籍中都介绍过,一个Class对象需要占用多大的内存空间。最权威的结论是:

    *非静态成员变量总合。(not static)

    *加上编译器为了CPU计算,作出的数据对齐处理。(c语言中面试中经常会碰到内存对齐的问题)

    *加上为了支持虚函数(virtual function),产生的额外负担。

    下面给出几个程序来看一下:

    复制代码
    #include <iostream>
    #include <cstdio>
    #include <string>
    using namespace std;
    class Car1{
    };
    
    void fun1(void)
    {
        int size =0;
        Car1 objCar;
        size = sizeof(objCar);
        printf("%s is %d
    ","Class Car1 Size",size);
    }
    
    class Car2{
    private:
        int nLength;
        int nWidth;
    };
    void fun2(void)
    {
        int size = 0;
        Car2 objCar;
        size = sizeof(objCar);
        printf("%s is %d
    ","Class Car2 Size",size);
    }
    
    class Car3{
    private:
        int nLength;
        int nWidth;
        static int sHight;
    };
    void fun3(void)
    {
        int size =0;
        Car3 objCar;
        size =sizeof(objCar);
        printf("%s is %d
    ","Class Car3 Size",size);
    }
    
    class Car4{
    private:
        char chLogo;
        int nLength;
        int nWidth;
        static int sHigh;
    };
    void fun4(void)
    {
        int size =0;
        Car4 objCar;
        size = sizeof(objCar);
        printf("%s is %d
    ","Class Car4 Size",size);
    }
    
    class Car5{
    public:
        Car5(){};
        ~Car5(){};
    public:
        void Fun(){};
    };
    
    void fun5(void)
    {
        int size =0 ;
        Car5 objCar;
        size = sizeof(objCar);
        printf("%s is %d
    ","Class Car5 Size",size);
    }
    
    class Car6{
    public:
        Car6(){};
        ~Car6(){};
    public:
        void Fun(){};
    private:
        int nLength;
        int nWidth;
    };
    void fun6(void)
    {
        int size = 0;
        Car6 objCar;
        size = sizeof(objCar);
        printf("%s is %d
    ","Class Car6 Size",size);
    }
    
    class Car7{
    public:
        Car7(){};
        virtual ~Car7(){};
    public:
        void Fun(){};
    };
    void fun7(void)
    {
        int size = 0;
        Car7 objCar;
        size = sizeof(objCar);
        printf("%s is %d
    ","Class Car7 Size",size);
    }
    
    class Car8{
    public:
        Car8(){};
        virtual ~Car8(){};
    public:
        void Fun(){};
        virtual void Fun1(){}
    };
    void fun8(void)
    {
        int size = 0;
        Car8 objCar;
        size = sizeof(objCar);
        printf("%s is %d
    ","Class Car8 Size",size);
    }
    
    int main()
    {
        fun1();
        fun2();
        fun3();
        fun4();
        fun5();
        fun6();
        fun7();
        fun8();
    }
    复制代码

    编译:g++ memAlign.cpp -o memAlign

    输出结果:

    复制代码
    Class Car1 Size is 1
    Class Car2 Size is 8
    Class Car3 Size is 8
    Class Car4 Size is 12
    Class Car5 Size is 1
    Class Car6 Size is 8
    Class Car7 Size is 8
    Class Car8 Size is 8
    复制代码

    ps:上述编译环境是在mac os下的g++

    下面我们具体来分析一下这几个情况:

    1、空类、单一继承的空类、多重继承的空类所占空间大小为:1(字节,下同);

    2、一个类中,虚函数本身、成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空间的;

    3、因此一个对象的大小≥所有非静态成员大小的总和;

    4、当类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针vPtr指向虚函数表VTable;

    5、虚继承的情况:由于涉及到虚函数表和虚基表,会同时增加一个(多重虚继承下对应多个)vfPtr(virtual function table)指针指向虚函数表vfTable和一个vbPtr(virtual base pointer)指针指向虚基表vbTable,这两者所占的空间大小为:8(或8乘以多继承时父类的个数);

    6、在考虑以上内容所占空间的大小时,还要注意编译器下的“补齐”padding的影响,即编译器会插入多余的字节补齐;(请参考《c和指针》)

    7、类对象的大小=各非静态数据成员(包括父类的非静态数据成员但都不包括所有的成员函数)的总和+ vfptr指针(多继承下可能不止一个)+vbptr指针(多继承下可能不止一个)+编译器额外增加的字节。

     参考:C++虚函数工作原理和(虚)继承类的内存占用大小计算

     在VC 6.0中,结果是

    复制代码
    Class Car1 Size is 1
    Class Car2 Size is 8
    Class Car3 Size is 8
    Class Car4 Size is 12
    Class Car5 Size is 1
    Class Car6 Size is 8
    Class Car7 Size is 4
    Class Car8 Size is 4
    复制代码

    主要的不同点是:在Car7和Car8,在VC 6.0中虚函数指针占用4个字节,在gcc编译器中占用8个字节。

            也可以换一种说法是virtual函数指针在VC下以4字节对齐,在gcc下是8字节对齐,这样解释就比较清楚了。

    二、编程实现成员在类或结构体中的偏移量

    代码如下所示:

    复制代码
     1 #include <cstdio>
     2 #include <iostream>
     3 #define pos(type,member) (&((type *)0)->member)
     4 
     5 class car{
     6 public:
     7     car(){}
     8     ~car(){}
     9 public:
    10     virtual void fun(){}
    11 private:
    12     int c;
    13 public:
    14     void print()
    15     {
    16         printf("%x
    ",pos(car,c));
    17     }
    18 };
    19 
    20 int main()
    21 {
    22     struct Node{
    23         int a ;
    24         char b;
    25         int c;
    26     };
    27     car objCar;
    28 //    printf("%x
    ",&((struct Node *)0)->b);
    29     printf("%x
    ",pos(struct Node,b));
    30     printf("%x
    ",pos(struct Node,c));
    31 //    printf("%x
    ",pos(class car,c));
    32     objCar.print();
    33     return 0;
    34 }
    复制代码

    其中关键的是找到函数能够实现计算成员在类中的偏移量,这里用了宏来实现的。

    #define pos(type,member) (&((type *)0)->member)

    (从地址0开始的一个type结构体或者类,其成员的地址就是成员所在类或结构体的偏移量)

    上述程序的输出结果就是:4 8 8

  • 相关阅读:
    一定要在3 20前完成所有的程序开发工作
    浅谈图像处理方向的就业前景[转)
    期待牛人指教的问题?
    vc6 7工程转vc8时的问题
    今天的工作计划
    定点数与浮点数区别
    difference between texRECT and tex2D
    Render to Texture
    不明白gluperpective的fovy参数
    批处理程序教程(转)
  • 原文地址:https://www.cnblogs.com/LUO77/p/5890624.html
Copyright © 2011-2022 走看看