码迷,mamicode.com
首页 > 其他好文 > 详细

sizeof系列——struct class union

时间:2015-05-10 17:28:45      阅读:130      评论:0      收藏:0      [点我收藏+]

标签:朋友   double   结构体   编译器   

struct:


struct MyStruct

{   

   double a;

   char   b;

   int    c;

};


sizeof(MyStrut)=?????

很多朋友会认为结果是: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)中续表指针的大小。




  



本文出自 “学习心得与笔记” 博客,请务必保留此出处http://cxdbk.blog.51cto.com/8808491/1650006

sizeof系列——struct class union

标签:朋友   double   结构体   编译器   

原文地址:http://cxdbk.blog.51cto.com/8808491/1650006

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!