第一段代码:
#include <iostream>
using namespace std;
class s{
char c1;
char c2;
int a;
};
int main(){
cout<<"sizeof(s):"<<sizeof(s)<<endl;
system("pause");
return 0;
}
第二段代码
#include <iostream>
using namespace std;
class s{
char c1;
int a;
char c2;
};
int main(){
cout<<"sizeof(s):"<<sizeof(s)<<endl;
system("pause");
return 0;
}
这两段程序看似结果是一样的,都是sizeof(s):6,但是其实是错的,第一段的结果是sizeof(s):8,第二段的结果是sizeof(s):12。
现在让我们来分析一下:
这里涉及到了字节对齐这个概念,对齐跟数据在内存中的位置有关,如果一个变量的地址正好位于它长度的整数倍,他就被称作自然对齐。比如在32位cpu下,假设一个整型变量从地址0x00000004开始存储,那它就是自然对齐的。为什么是这样的呢?因为我们知道32位cpu每次是一下子取32bit的数据的,也就是4byte,也就是说一开始0x00000000,0x00000001,0x00000002,0x00000003这四个地址里的数据一下子就被cpu读取了,下面0x00000004~0x00000007正好存储的就是int型的数据(int型数据不是占4字节吗?啊,这里我说的是一般情况下的int型,有些系统int型不是占4字节的),所以要取这个int型的时候也是一下子就取走了。
但是如果这个int型变量开始的地址不是0x00000004,而是0x00000005,那么,就会有一个byte的部分存储到了0x00000008这个地址里去了,而这一个byte可就得等到cpu的下次取数时才能取出来了,也就是说要取完整这个int型数据,我们得取两次,而且还得把两次取出来的结果拼起来,还原成一个完整的int,这不就浪费时间了吗。所以编译器就会为了节省时间进行字节对齐,但是这是一种以空间换时间的方法,这也就造成了上面的结果。
下面让我们看看字节对齐的四个重要的基本概念:
1.数据类型自身的对齐值:
对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
3.指定对齐值:#pragma pack (value)时的指定对齐值value。
4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
那么第二个为何又不一样了呢,因为申请存储空间的顺序变了呀,先是一个char,再来的是一个int,最后才是一个char。
如果还是不懂呢,请移步http://blog.youkuaiyun.com/21aspnet/article/details/6729724,这位大牛讲得更全面详细,最关键的是最后有一副图。