struct:
struct MyStruct
{
double a;
char b;
int c;
};
sizeof(MyStrut)=?????
很多朋友会认为结果是:8(sizeof(a))+1(sizeof(b))+4(sizeof(c))=13
但是当我们在vs上运行输出的结果是 16,这是为什么呢?
这是编译器为了提高cup的存储速度对一些起始地址进行了"对齐"处理.
虽然对齐原则和编译器有关联但是以下的原则是必须遵守的:
结构体变量的首地址能够被其最宽基本类型成员的大小整除。
结构体每个成员相对于结构体首地址偏移量都是成员大小的整数倍,不够就进行字节填充。
结构体的总大小为最宽数据成员的整数倍,不够就字节填充。
所以再将目光转向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
原文地址:http://cxdbk.blog.51cto.com/8808491/1650006