sizeof系列——struct class union

来源:互联网 发布:ubuntu安装 中文语言包 编辑:程序博客网 时间:2024/06/17 19:08

struct:

struct MyStruct

{   

   double a;

   char   b;

   int    c;

};

sizeof(MyStruct)=?????

很多朋友会认为结果是:8(sizeof(a))+1(sizeof(b))+4(sizeof(c))=13

但是当我们在vs上运行输出的结果是 16,这是为什么呢?

这是编译器为了提高cup的存储速度对一些起始地址进行了"对齐"处理.

虽然对齐原则和编译器有关联但是以下的原则是必须遵守的:

  1. 结构体变量的首地址能够被其最宽基本类型成员的大小整除。

  2. 结构体每个成员相对于结构体首地址偏移量都是成员大小的整数倍,不够就进行字节填充。

  3. 结构体的总大小为最宽数据成员的整数倍,不够就字节填充。

所以再将目光转向MyStruct:

第一个变量a首地址偏移量为0,是sizeof(a)=8的整数倍,所以占用8+0=8个字节。

第二个变量b首地址偏移量为8,是sizeof(b)=1的整数倍,所以占用1个字节,将b放在偏移量为8的地方。

第三个变量c首地址偏移量8+1=9,不是sizeof(c)=4的整数倍所以进行字节填充9+3=12(离9最近的4的倍数),变量c占用4个字节。

综上:8+1+3+4=16 16是最大数据类型double=8的整数倍(不用补充字节),所以最后结果是16.

如果我们将MyStruct的数据位置换一下

struct MyStruct

{   

   char a;

   double   b;

   int    c;

};

那么sizeof(MyStruct )的结果会是

sizeof(a)=1;

sizeof(b)=8;

sizeof(c)=4;

(1+7+8+4)=20;(包含了填充字节);

但是20不是8的整数倍所以填充字节20+4=24(离20最近的8的整数倍)

当然我们也可以用#pragam pack(n)来终结这种丧心病狂的对齐方式

eg:

#pragam pack(push)//保存对齐状态

#pragam pack(4)(以4字节方式对齐)

struct Test

   char a;

   double b;

   int   c;

};

#pragam pack(pop)


原则:

若n>变量字节 采用默认对齐方式

若n<变量字节 采用n的倍数对齐方式

若n>所有变量(单个)的字节数,那么总大小为最大变量的整数倍,否则为n的整数倍

sizeof(Test)=1+3+8+4=13 补齐3个字节=16;

若把#pragam pack(4)改为#pragam pack(16)

sizeof(Test)=1+7+8+4+4=24;


union:

union Test

{

   int a;

   double b;

   char c;

};

sizeof(Test)

sizeof(a)=4;

sizeof(b)=8;

sizeof(c)=1;

sizeof(Test)以最长为所有字节 8 又因为8是8的倍数所以最后为8(union以单个最长字节对齐


class:

一、个空类

class A

};

    求sizeof的结果是1,因为即使是没有成员之类的,一个类存在,至少都要给他一个空间,不然就没有存在的意义了。

二、简单的类

class A

{

    int a;

    virtual fun();

}

    这个也好求,就是sizeof(A.a)+4(指向虚表的指针)

三、子类普通继承、父类中不含虚函数

class  A

{

    int a;

}

class B:public A

{

     int b;

     virtual fun();

}

sizeof(B)=sizeof(A)+sizeof(B.b)+4(指向虚表指针)

四、子类普通继承、父类含虚函数

class  A

{

    int a;

    virtual fun1();

}

class B:public A

{

     int b;

     virtual fun();

}

sizeof(B)=sizeof(A)-4(sizeof(A)中有一个指向虚表的指针)+sizeof(B.b)+4(指向虚表指针)

因为普通继承,子类和父类的虚函数存放在同一个虚表中,所以,只需要存一个指向续表的指针即可;

五、子类虚继承、父类不含虚函数

class  A

{

    int a;

   

}

class B:virtual public A

{

     int b;

     virtual fun();

}

sizeof(B)=sizeof(A)+4(指示父类存放空间的起始偏移量)+sizeof(B.b)+4(指向B的虚表的指针)

六、子类虚继承、父类含虚函数

class  A

{

    int a;

    virtual fun1();

   

}

class B:virtual public A

{

     int b;

     virtual fun();

}

sizeof(B)=sizeof(A)+4(指示父类存放空间的起始偏移量)+sizeof(B.b)+4(指向B的虚表的指针)

虚继承时,父类和子类的虚函数表分开放,所以,分别存储两个指向对应续表的指针,因而不用减去sizeof(A)中续表指针的大小。


0 0
原创粉丝点击