标签:
先上代码:
struct A { int a; double d; char b; short c; };
a占用4字节,由于d占用8字节,且d需要在8字节处对齐,因此a不仅有4字节存放内容,并且占另外的4个字节使得d位于8字节处。由于c需要在2字节处对齐,所以b占用了2个字节,c占用两个字节,目前总共是20字节,但是整个结构体A根据最大字节对齐,因此为8字节对齐,为了使得类型位struct A的数组的下一个元素处于正确的对齐位置,此结构体还要额外占用4字节,总共是20+4=24字节。
内存分配见下图:(其中红颜色的为对齐需要的额外内存,黑颜色的为变量内容所占字节数)
再来看看接下来的代码,比上面的代码多了一个 #pragma pack(4)
#pragma pack(4) struct A { int a; double d; char b; short c; };sizeof(struct A)为16。分析:
#pragma pack(4) 使得对齐方式为4字节对齐,因此对齐方式大于4字节的类型都要以4字节方式对齐,因此double也是以4字节方式对齐,struct A也是以4字节方式对齐。所以a只占用4字节,d占用接下来的8个字节,但是c是2字节对齐,比4要小,因此还是以2字节对齐方式对齐,所以b除了自己一个字节存储内容外,还要额外占用1个字节,使得c可以在2字节处对齐。此时struct A总共占4+8+2+2=16,而16是4的倍数,保证了struct A本身的对齐方式,因此结果为16。
内存分布图如下:
总结:若没有规定对齐方式,则结构体内的元素按照所占用的字节数进行对齐,而结构体按照元素最大字节对齐方式对齐;
若规定了对齐方式,例如规定4字节对齐,则对齐方式小于4字节的元素依然按照自身的对齐方式保持对齐,否则对齐方式大于4字节的元素按照4字节方式对齐。
基本类型的对齐方式(默认在32 bit环境下):bool-->1,char-->1,short-->2,int-->4,long-->4,long long-->8,float-->4,double-->8
首先看看普通继承:
class Base { public: virtual int init(); protected: int a; char b; }; class Derived : public Base { public: virtual int init(); protected: char b; int a; };在vs2010中得:sizeof(Base)=12,sizeof(Derived)=20。
分析:Base中含有虚函数,则有个虚指针vfptr_Base,占用4个字节,int占用4个字节,b占用一个自己,此时共有4+4+1=9个字节,而Base自身的对齐方式为4字节,因此最后补齐4的倍数为12字节。内存分配图如下:(c++标准规定虚函数表指针必须位于类实例的开头 参考于http://www.cppblog.com/xczhang/archive/2008/01/20/41508.html)
Derived含有一个虚指针vfptr_derived,占用四个字节,然后含有Base中的int a和char b,其中Base::a占用四个字节,Base::b占用一个字节,此时Base完成,但需要补齐四字节(这里是根据vs2010中的Base::b和Derived::b的地址间距判断的,属于个人猜想,如有不对还望指教),此时占用字节数为4+4+4=12;接下来是Derived的成员变量了,其中Derived::b占用一个字节,而Derived::a需要在4字节处对齐,因此Derived::b之后有三个多余字节用于Derived::a的对齐使用,所以Derived的成员变量部分占用的字节数为1+3+4=8;因此Derived占用12+8=20个字节。内存分配如下:
但是在g++环境下,sizeof(Derived)为16,而sizeof(Base)依然为12,通过观察Derived::Base::a,Derived::Base::b,Derived::b以及Derived::a的地址发现内存分布如下图:
可见不同的编译器拥有不同的实现,因此要分清楚是哪个编译器。另外极力推荐这个博文,我个人认为非常有帮助http://www.cppblog.com/xczhang/archive/2008/01/20/41508.html
virtual继承和多重继承先不整理了,这个搞了我一天,我发现写博客还是比较累的,先休息休息。
标签:
原文地址:http://blog.csdn.net/zhenxihongyan/article/details/44747811