深入了解sizeof计算规则

  • Post author:
  • Post category:其他



点击前往sizeof计算规则


union大小计算



系统及基本变量大小



系统

由于系统版本不一样,计算出来的大小会有差异。我的电脑系统如下:

在命令行中输入uname -a

root:xnu-8019.80.24~20/RELEASE_X86_64 x86_64

我的电脑是64位。



基本变量大小

#include <iostream>
#include <stdio.h>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;



int main()
{
    int a0[0], a1[1], a10[10];
    char *pc;
    int *pi;


    printf("size of char = %d\n", sizeof(char)); // 1
    printf("size of bool = %d\n", sizeof(bool)); // 1
    printf("size of short = %d\n", sizeof(short)); // 2
    printf("size of integer = %d\n", sizeof(int)); // 4
    printf("size of long = %d\n", sizeof(long)); // 由系统决定64位为8
    printf("size of long long = %d\n", sizeof(long long)); // 8

    // 数组大小 = 元素大小*个数 :: 0就是0个元素占用空间为0.
    // 数组在计算class内存时,可以认为定义了N个连续的变量。

    printf("size of a0 = %d\n", sizeof(a0)); // 0
    printf("size of a1 = %d\n", sizeof(a1)); // 4
    printf("size of a10 = %d\n", sizeof(a10)); // 40

    // 任何指针大小都为8字节
    printf("size of int pointer = %d\n", sizeof(pi)); // 8
    printf("size of char pointer = %d\n", sizeof(pc)); // 8

    return 0;
}
/*
代码输出
size of char = 1
size of bool = 1
size of short = 2
size of integer = 4
size of long = 8
size of long long = 8
size of a0 = 0
size of a1 = 4
size of a10 = 40
size of int pointer = 8
size of char pointer = 8
联合体union的大小取决于他所有成员中占用空间最大的一个成员的大小。
*/



class中内存占用规则

  1. 将所有元素用到的内存从上到下排列。(有一些隐藏的元素比如虚函数表指针)。
  2. 调整位置,将每个元素开始地址调整到自身大小的整数倍。
  3. 补齐,如果整个大小不是最大元素的整数倍则向后补齐达到整数倍。



多重继承情况(虚函数)

先对基类继承顺序从前到排序,基类里面排列规则是虚函数指针排第1,后面加上数据字段。最后放置本类内的元素。然后按照上述规则进行调整位置和补齐。最后补齐的标准是所有元素中最大值的整数倍。



实例分析

普通情况在上述链接中已经有举例,这里主要分析一下多重继承带虚函数的情况



虚函数

#include <iostream>
#include <stdio.h>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;


class A {
    int a[0];
};

class B {
};

class C {
public:
    virtual void print1() {};
};

class D : public C {
public :
    void print1() {}

    short x;
};


class S {
public:
    S() { cout << "S()" << endl; }

    virtual ~S() { cout << "~S()" << endl; }

    static int a;
};

int main() {
    std::cout << sizeof(A) << std::endl; // 0
    std::cout << sizeof(B) << std::endl; // 1
    std::cout << sizeof(C) << std::endl; // 8
    std::cout << sizeof(D) << std::endl; // 16
    std::cout << sizeof(S) << std::endl; // 8
    return 0;
}

A中是一个长度为0的数组占用0.

B是一个空对象,底层实现占用1.

C对象中有一个虚函数指针占用8字节。

D有一外虚函数指针再接一个short, 最后对齐到8的倍数16.

S中static算一个全局变量,不能算在S的内存中,一个虚函数指针占用内存8.



多重继承



#include <iostream>
#include <stdio.h>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;

class D {
public:
    virtual void fund(){
    }
};

class A {
public:
    int b;
    virtual void funa(){
        cout<<"fa"<<endl;
    }
};


class E {
    short e;
};

class B:public A,D{
public:
    short a;
    void fund(){
        cout<<"fb"<<endl;
    }
};

class C:public D,A{
public:
    short a;
};


int main()
{
    cout<<sizeof(B)<<endl;
    cout<<sizeof(C)<<endl;
    return 0;
}

/*
32
24
*/

对于B排布如下

字段 占用大小 起始地址
vta 8 0
b 4 8
vtd 8 16(上一行实际用到12,由于起始地址要等于自身的倍数,所以要从16开始)
a 2 24

字段a结束地址是26,最终大小得最大字段(指针为8)的倍数,所以大小为32。

对于C排布如下

字段 占用大小 起始地址
vtd 8 0
vta 8 8
b 4 16
a 2 18

字段a结束地址是18,最终大小得最大字段(指针为8)的倍数,所以大小为24。


#include<iostream>
using namespace std;


class A
{
};

class B
{
    char ch;
    virtual void func0()  {  }
};

class C
{
    char ch1;
    char ch2;
    virtual void func()  {  }
    virtual void func1()  {  }
};

class D: public A, public C
{
    int d;
    virtual void func()  {  }
    virtual void func1()  {  }
};
class E: public B, public C
{
    long e;
    virtual void func0()  {  }
    virtual void func1()  {  }
};

int main(void)
{
    cout<<"B="<<sizeof(B)<<endl;    //result=16
    cout<<"C="<<sizeof(C)<<endl;    //result=16
    cout<<"D="<<sizeof(D)<<endl;    //result=16
    cout<<"E="<<sizeof(E)<<endl;    //result=32
    return 0;
}

/*
B=16
C=16
D=16
E=40
*/



虚继承

虚继承子类会产生自己的虚函数表指针。

父类没有成员数据时,不会产生新的指针表。


#include <iostream>
#include <stdio.h>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;


class A {
public:
    virtual void print1() {};
};

class C {
public:
    int a;
    virtual void print1() {};
};

class D : virtual public C {
public :
    virtual void print1() {}
};


class E : public  C {
public :
    virtual void print1() {}
};


class F : virtual public A {
public :
    virtual void print1() {}
};

int main() {
    std::cout << sizeof(C) << std::endl; // 16 虚函数表+一个变量大小
    std::cout << sizeof(D) << std::endl; // 24 产生子类虚函数表
    std::cout << sizeof(E) << std::endl; // 16 非虚继承延用父类虚函数表
    std::cout << sizeof(F) << std::endl; // 8 父类无成员变量时不会产生新的虚函数表指针

    return 0;
}




版权声明:本文为chenbb1989原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。