Sizeof的计算看内存分配

本文记录了有关sizeof的一些计算,主要有下面的四种情况:(如有错误,敬请留言)

  1. 使用sizeof()计算普通变量所占用的内存空间
  2. sizeof计算类对象所占用空间的大小-用到了字节对齐
  3. sixeof计算含有虚函数的类对象的空间大小
  4. sizeof计算虚拟继承的类对象的空间大小

使用sizeof()计算普通变量所占用的内存空间

#include <iostream>
#include <stdlib.h>
using namespace std;

//如果数组变量被传入函数中做sizeof()运算,则和指针的运算没有区别。
void Func( char str[100] )
{
    cout<<"Fun: == "<<sizeof(str)<<endl;//4字节的指针
}

int main()
{
    char str[] = "Hello";
    char *p = str;
    int n = 10;

    cout<<"str == "<<sizeof(str)<<endl;
    //结果=6=strlen("Hello")+1;数值中要留一个元素保存字符串结束符
    Func(str);

    //2个结果都是4,win32下,指针和int都是4字节
    cout << "p ==" << sizeof(p) << endl;
    cout << "n ==" << sizeof(n) << endl;//结果4

    void *q = malloc(100);//100字节的堆内存
    cout << "void * == " << sizeof(q) << endl;
    //还是4(指针类型的大小)

    char *ch = (char *)malloc(sizeof(char)*10);
    cout << "char * == " <<sizeof(ch) << endl;
    //还是4(指针类型的大小)
    
    return 0;
}
//数组和指针的sizeof()是有区别的。
//对于指针,不论何种类型,其大小都是4字节的。

通过上面的示例,我们可以看到:sizeof计算的都是数据类型占用空间的大小,除了一种情况,就是初始化char str[]="Hello"的时候,sizeof计算的是字符串的长度+1.


sizeof计算类对象所占用空间的大小-用到了字节对齐

#include <iostream>
using namespace std;

class A
{
public:
    int i;//4
};
class AA
{
public:
    double d;
    int i;//8+4+4(补全)
};
class B
{
public:
    char ch;//1
};
class C
{
public:
    int i;
    short j;//4+2+2(补全)
};
class D
{
public:
    int i;
    short j;
    char ch;//4+2+1+1(补全)
};
class E
{
public:
    int i;
    int ii;
    short l;
    char ch;
    char chr;//4+4+2+1+1
};
class F
{
public:
    int i;
    int ii;
    int iii;
    short j;
    char ch;
    char chr;//4+4+4+2+1+1
};
class FF
{
public:
    short j;
    int i;
    char ch;
    int ii;
    char chr;
    int iii;//2+2(补全)+4+1+3(补全)+4+1+3(补全)+4=24
};
int main()
{
    cout<<"sizeof(double) == "<<sizeof(double)<<endl;//4字节
    cout<<"sizeof(float) == "<<sizeof(float)<<endl;//4字节
    cout<<"sizeof(int) == "<<sizeof(int)<<endl;//4字节
    cout<<"sizeof(short) == "<<sizeof(short)<<endl;//2
    cout<<"sizeof(char) == "<<sizeof(char)<<endl<<endl;//1

    cout<<"sizeof(A) == "<<sizeof(A)<<endl;
    cout<<"sizeof(AA) == "<<sizeof(AA)<<endl;//最宽的类型是8字节的。
    cout<<"sizeof(B) == "<<sizeof(B)<<endl;
    cout<<"sizeof(C) == "<<sizeof(C)<<endl;
    cout<<"sizeof(D) == "<<sizeof(D)<<endl;
    cout<<"sizeof(E) == "<<sizeof(E)<<endl;
    cout<<"sizeof(F) == "<<sizeof(F)<<endl;
    cout<<"sizeof(FF) == "<<sizeof(FF)<<endl;//同样的类型个数,只是顺序变了,就不一样了。
    return 0;
}
    字节对齐的准则
  1. 结构体的首地址能够被其最宽基本类型成员的大小所整除。
  2. 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍(编译器会在成员之间加上填充字节)如FF
  3. 结构体的总大小为结构体中最宽基本类型成员大小的整数倍(编译器会在最后成员的后面填充字节)如AA

sixeof计算含有虚函数的类对象的空间大小

#include <iostream>
using namespace std;
class Base
{
public:
    Base(int x):a(x){}
    void print()
    {
        cout<<"base"<<endl;
    }
private:
    int a;
};
class Dervied:public Base
{
public:
    Dervied(int x):Base(x-1),b(x){}
    void print()
    {
        cout<<"Dervied"<<endl;
    }
private:
    int b;
};
class A
{
public:
    A(int x):a(x){}
    virtual void print()
    {
        cout<<"A"<<endl;
    }
private:
    int a;
};
class B:public A
{
public:
    B(int x):A(x-1),b(x){}
    virtual void print()
    {
        cout<<"B"<<endl;
    }
private:
    int b;
};

int main()
{
    Base obj1(1);
    cout<<"size of base obj1 is "<<sizeof(obj1)<<endl;
    Dervied obj2(2);
    cout<<"size of Dervied obj2 is "<<sizeof(obj2)<<endl;

    A a(1);
    cout<<"size of A obj is "<<sizeof(a)<<endl;
    B b(2);
    cout<<"size of B obj is "<<sizeof(b)<<endl;
    return 0;
}
  1. Base类:占用内存大小是sizeof(int),print()不占用内存空间。4
  2. Dervied类:比Base类多了一个整形成员,因而多4个字节。8
  3. A类:因为含有虚函数,因此占用内存除了一个整型变量之外,还包括一个隐含的虚表指针成员,一共8字节
  4. B类:比A类多了一个整型成员。所以12字节。

普通函数不占用内存,只要有虚函数,就会占用一个指针大小的内存,原因,系统多用了一个指针维护这个类的虚函数表, 并注意到,这个虚函数无论含有多少项(类中含有多少个虚函数)都不会再影响类的大小了。


sizeof计算虚拟继承的类对象的空间大小

#include <iostream>
using namespace std;
class A{};
class B{};
class C:public A,public B{};
class D:virtual public A{};
class E:virtual public A,virtual public B{};
class F
{
public:
    int a;
    static int b;
};
int F::b = 10;
int main()
{
    cout<<"sizeof(A) =="<<sizeof(A)<<endl;
    cout<<"sizeof(B) =="<<sizeof(B)<<endl;
    cout<<"sizeof(C) =="<<sizeof(C)<<endl;
    cout<<"sizeof(D) =="<<sizeof(D)<<endl;
    cout<<"sizeof(E) =="<<sizeof(E)<<endl;
    cout<<"sizeof(F) =="<<sizeof(F)<<endl;
    return 0;
}
  1. A类为空,编译器会安排一个char类型给他,用来标记每一个对象。1字节
  2. C类,多重继承,依然1字节
  3. D类,虚拟继承A,编译器会安排一个指向父类的指针,为4.因为有了指针,所以不会安排char类型了。
  4. E类,虚拟继承多个,但是只要一个指针就可以了。
  5. F类,静态成员的空间不在类的实例中,而是像全局变量一样,在静态存储区,被每一个类的实例共享。

posted @ 2015-06-22 20:48  [0]  阅读(1242)  评论(1编辑  收藏  举报