#include <iostream>
using namespace std;
union u
{
double a ;
int b ;
};
union u2
{
char a[13] ;
int b ;
};
union u3
{
char a[13] ;
char b ;
};
int main()
{
cout<<sizeof(u)<<endl ;
cout<<sizeof(u2)<<endl ;
cout<<sizeof(u3)<<endl ;
return 0 ;
}
程序解析:
上述程序定义了3个联合体u1、u2和u3,我们知道联合体的大小取决于它所有的成员中占用空间最大的一个成员的大小,并且对于复合数据类型,如union、struct、class的对齐方式为成员中最大的成员对齐方式。
(1)对于u来说,大小就是最大的double类型成员a了,即sizeof(u) = sizeof(double) = 8
(2)对于u2来说,最大的空间是char[13]类型的数组,这里要注意,由于它的另一个成员int b的存在,u2的对齐方式变成4,也就是说,u2的大小必须在4的对齐上,所以占用的空间变为最接近13的对齐,即16
(3)对于u3来说,最大的空间是char[13]类型的数组,即sizeof(u3) = 13
这里又出现了CPU对齐的问题,所以编译器会尽量把数据放在它的对齐上以提高内存的命中率,对齐是可以更改的,使用#pragma pack(x)可以改变编译器的对齐方式,C++固有类型的对齐取编译器对齐方式与自身大小中较小的一个。例如:指定编译器按2对齐,int类型的大小是4,则int的对齐为2和4中较小的2,在默认的对齐方式下,因为几乎所有的数据类型都不大于默认的对齐方式8(除了long double),所以所有的固有类型的对齐方式可以认为就是类型自身的大小,例如下面的程序:
#include <iostream>
using namespace std;
#pragma pack(2)
union u
{
char buf[9] ;
int a ;
};
int main()
{
cout<<sizeof(u)<<endl ;
return 0 ;
}
C++固有类型的对齐取编译器对齐方式为2,所以int的对齐也变成了2(int自身对齐为4),u的对齐取成员中最大的对齐,也是2,所以此时sizeof(u) = 10,如果注释上面的第4行,int 的对齐使用4,u的对齐取成员中最大的对齐,也是4,所以此时sizeof(u) = 12 。
#pragma pack的作用:
#include <iostream>
using namespace std;
#pragma pack(1)
struct test
{
char c ;
short s1 ;
short s2 ;
int i ;
}
int main()
{
cout<<sizeof(test)<<endl ;
return 0 ;
}
解析:
上述代码中用#pragma pack将对齐设置为1,由于结构体test中的成员s1,s2和i的自身对齐分别为2、2和4,都小于1,因此他们都是用1作为对齐,sizeof(test) = 1+2+2+4 = 9 ,倘若注释掉#pragma pack,则编译器默认对齐为8,所以各个成员自身的对齐都小于8,因此它们使用自身的对齐,sizeof(test)=1+1(补齐)+2+2+2(补齐)+4 = 12