a. 基本类型:所有的基本类型都有相应的对齐参数,编译器在编译时,会用全局的对齐参数和当前类型的对齐参数中较小的一个进行对齐。比如,编译时指定暗8bytes对齐(用#pragma pack(8)实现之),可是由于一个char变量的大小为一个byte,所以最后还是按1byte对齐。
b. 复合类型:复合类型的对齐原则,就是取其成员变量数据类型的字节数的最大者和在编译时指定的对齐数两者之间较小的字节数进行对齐。如果没有用诸如#pragma pack指定全局对齐数,则该复合类型的对齐数就是其成员变量数据类型字节数之最大者。
#include <iostream>
using namespace std;
// #pragma pack(4)
class PatClass0 // PatClass0的对齐数为1。因为其成员变量c1的数据类型为char,而sizeof(char)=1
{
private:
char c1;
};
class PatClass1 // PatClass1的对齐数为1。因为其成员变量c1和c2的数据类型均为char,而sizeof(char)=1
{
private:
char c1;
char c2;
};
class PatClass2 // PatClass2的对齐数为2。因为其成员变量c1的数据类型均为char,sizeof(char)=1,
{ // 成员变量c2的数据类型为short,而sizeof(short)=2。
private: // 取其字节数最大者,即2。
char c1;
short c2;
};
class PatClass3 // PatClass3的对齐数为4。因为其成员变量c1的数据类型均为char,sizeof(char)=1,
{ // 成员变量c2的数据类型为int,而sizeof(int)=4。
private: // 取其字节数最大者,即4。
char c1;
int c2;
};
class PatClass4 // PatClass4的对齐数为8。因为其成员变量c1的数据类型均为char,sizeof(char)=1,
{ // 成员变量c2的数据类型为double,而sizeof(8)=8。
private: // 取其字节数最大者,即8。
char c1;
double c2;
};
class PatClass5 // PatClass5的对齐数为4。见PatClass3说明
{
private:
int c1;
};
class PatClass6 : public PatClass5 // PatClass6的对齐数为4。这是因为它继承了PatClass5,PatClass5中的成员
{ // 变量c1也会被编译器安插在类PatClass6的对象中(尽管不能对其进行普通意
private: // 义上的访问),而c1的数据类型为int,sizeof(int)=4。所以PatClass6的对齐数
char c2; // 为4。
};
int main(void)
{
PatClass0 c0;
PatClass1 c1;
PatClass2 c2;
PatClass3 c3;
PatClass4 c4;
PatClass5 c5;
PatClass6 c6;
cout << "the size of PatClass0 object is: " << sizeof(c0) << endl;
// PatClass0的对齐数为1byte,它只有一个成员变量char c1,因此其对象c0的大小为1byte
cout << "the size of PatClass1 object is: " << sizeof(c1) << endl;
// PatClass1的对齐数为1byte,它有两个成员变量char c1和char c2,因此其对象c1的大小为2bytes
cout << "the size of PatClass2 object is: " << sizeof(c2) << endl;
// PatClass2的对齐数为2bytes,它有一个成员变量char c1和一个成员变量short c2,合起来为3bytes,由于其
// 对齐数为2bytes,因此需要填充1byte,才能变成2的倍数。故此其对象c2的大小为4bytes。
cout << "the size of PatClass3 object is: " << sizeof(c3) << endl;
// PatClass3的对齐数为4bytes,它有一个成员变量char c1和一个成员变量int c2,合起来为5bytes,由于其
// 对齐数为4bytes,因此需要填充3bytes,才能变成4的倍数。故此其对象c3的大小为8bytes。
cout << "the size of PatClass4 object is: " << sizeof(c4) << endl;
// PatClass4的对齐数为8bytes,它有一个成员变量char c1和一个成员变量double c2,合起来为9 bytes,由于
// 其对齐数为8bytes,因此需要填充7bytes,才能变成8的倍数。故此其对象c4的大小为16 bytes。
cout << "the size of PatClass5 object is: " << sizeof(c5) << endl;
// PatClass5的对齐数为4 bytes,它只有一个成员变量int c1,合起来为4bytes,刚好是其对齐数的倍数。
// 故此其对象c5的大小为4 bytes。
cout << "the size of PatClass6 object is: " << sizeof(c6) << endl;
// PatClass6的对齐数为4 bytes,它有一个成员变量char c2,并从PatClass5中继承来了int c1,合起来为5bytes,
// 因此需要填充3bytes,才能变成4的倍数。故此其对象c6的大小为8 bytes。
return 0;
}
输出结果为:
如果用#pragma pack(4)(在上面的程序中被注释了)指定全局对齐数为4bytes,结果如下:
其实这样的指定,只影响到了PatClass4,因为只有它有一个double成员变量,而sizeof(double)=8bytes,其他各类
均没有数据类型超过4bytes的。在前面曾经提及,一个类对象的内存对齐数 = min(指定的全局对齐数,成员变量数据
类型字节数最大者),因此在这个例子中PatClass4类型的对象的对齐数应该为4bytes。在PatClass类型的对象c4中,
成员变量double c2占8bytes,另外一个成员变量char c1占1byte,合起来一共9 bytes,因此要最小填充3 bytes,
才能成员对齐数 4 的倍数,即此时 PatClass4 类型的对象的大小为 12bytes 。