1.结构体的第一个元素地址必须是0x…..0(是受内存对齐这个影响产生的结果)
2.结构体成员地址是通过对齐规则和自身大小共同影响的,规则如下:
如果设定对齐方式为n个字节对齐,而某结构体成员大小为m,那么该结构体成员的地址必须为min(n,m)的整数倍,比如double在64位平台是8字节,指定对齐方式为1个字节对齐,则地址随意,若为2个字节对齐,则地址只能是0 2 4 8
3.通过以上方式,即可算出结构体所有成员(附带填充所占字节)的大小q,而结构体的大小必须为大于q的min(n,maximum)的最小整数倍(n语义同上,maxiumum为最大的成员字节数)
下面我们来通过实例来搞懂上面的规则
#include <iostream>
using std::cout;
using std::endl;
#pragma pack(1)
struct Test {
char c; // 1 byte
double d; // 8 byte
int i; // 4 byte
short s; // 2 byte
float f; // 4 byte
};
#pragma pack()
#pragma pack(2)
struct Test2 {
char c; // 1 byte
double d; // 8 byte
int i; // 4 byte
short s; // 2 byte
float f; // 4 byte
};
#pragma pack()
#pragma pack(8)
struct Test8 {
char c; // 1 byte
double d; // 8 byte
int i; // 4 byte
short s; // 2 byte
float f; // 4 byte
};
#pragma pack()
int main() {
//Test结构体以1字节对齐,总大小为1的倍数 因此为所有成员大小之和即可无需填充
Test test;
printf("Test 以%ld byte 对齐\n",alignof(Test));
printf("Test结构体大小: %ld\n",sizeof(Test));
printf("Test.c address: %p\n",&test.c);
printf("Test.d address: %p\n",&test.d);
printf("Test.i address: %p\n",&test.i);
printf("Test.s address: %p\n",&test.s);
printf("Test.f address: %p\n",&test.f);
//Test结构体以2字节对齐,总大小必须为2的倍数,成员与成员填充之和为(可以通过地址相减加尾元素大小) 20为2的倍数无需填充
Test2 test2;
printf("Test2 以%ld byte 对齐\n",alignof(Test2));
printf("Test2结构体大小: %ld\n",sizeof(Test2));
printf("Test2.c address: %p\n",&test2.c);
printf("Test2.d address: %p\n",&test2.d);
printf("Test2.i address: %p\n",&test2.i);
printf("Test2.s address: %p\n",&test2.s);
printf("Test2.f address: %p\n",&test2.f);
//Test结构体以8字节对齐,总大小必须为8的倍数,成员与成员填充之和为 27不为8的倍数,继续填充直到32
Test8 test8;
printf("Test8 以%ld byte 对齐\n",alignof(Test8));
printf("Test8结构体大小: %ld\n",sizeof(Test8));
printf("Test8.c address: %p\n",&test8.c);
printf("Test8.d address: %p\n",&test8.d);
printf("Test8.i address: %p\n",&test8.i);
printf("Test8.s address: %p\n",&test8.s);
printf("Test8.f address: %p\n",&test8.f);
return 0;
}