当时对内存对齐与补齐也不太懂,直接说了一句int类型占4个字节,char类型占1个字节,总共占5个字节。当时面试官也没说对错。后来回来和室友讨论才知道还要考虑内存补齐。所以在32位系统中一共要占8个字节。
最近恰好在牛客网刷题时候又遇到了这个问题,所以彻底学习了一下。
这是一个摘自牛客网的例题:
struct One{ double d; char c; int i; } struct Two{ char c; double d; int i; } 问在#pragma pack(4)和#pragma pack(8)的情况下,结构体的大小分别是多少?答:首先在#pragma pack(4)情况下,按照内存对齐的原则,struct One中的d占据0-7字节(offset=0开始,double类型占8个字节)。第二个成员c占据8字节(char类型占1个字节,对齐系数是4,两者中1较小,所以偏移地址必须是1的倍数,最近的1的倍数是8,所以i从8开始占1个字节)。第三个成员i占据12-15字节(int类型占4个字节,对齐系数是4,两者中4较小,所以偏移地址必须是4的倍数,最近的4的倍数是12,所以i从12开始占4个字节,前面的9-11三个字节对齐。)。而struct One中最大的数据成员是double型,占8个字节,对齐系数是4,两者中4较小,内存补齐的的地址必须是4 的倍数,而下一个字节刚好是16,是4的倍数,所以不需要内存补齐。所以在#pragma pack(4)情况下,struct One所需内存为16字节。struct Two中的c占据0字节(offset=0开始,char类型占1个字节)。第二个成员d占据4-11字节(double类型占8个字节,对齐系数是4,两者中4较小,所以偏移地址必须是4的倍数,最近的4的倍数是4,所以i从4开始占8个字节,前面的1-3三个字节对齐。)。第三个成员i占据12-15字节(int类型占4个字节,对齐系数是4,两者中4较小,所以偏移地址必须是4的倍数,最近的4的倍数是12,所以i从12开始占4个字节)。而struct Two中最大的数据成员是double型,占8个字节,对齐系数是4,两者中4较小,内存补齐的的地址必须是4 的倍数,而下一个字节刚好是16,是4的倍数,所以不需要内存补齐。所以在#pragma pack(4)情况下,struct Two所需内存为16字节。在#pragma pack(8)情况下,按照内存对齐的原则,struct One中的d占据0-7字节(offset=0开始,double类型占8个字节)。第二个成员c占据8字节(char类型占1个字节,对齐系数是8,两者中1较小,所以偏移地址必须是1的倍数,最近的1的倍数是8,所以i从8开始占1个字节)。第三个成员i占据12-15字节(int类型占4个字节,对齐系数是8,两者中4较小,所以偏移地址必须是4的倍数,最近的4的倍数是12,所以i从12开始占4个字节,前面的9-11三个字节对齐。)。而struct One中最大的数据成员是double型,占8个字节,对齐系数是8,两者中8较小,内存补齐的的地址必须是8 的倍数,而下一个字节刚好是16,是8的倍数,所以不需要内存补齐。所以在#pragma pack(8)情况下,struct One所需内存为16字节。struct Two中的c占据0字节(offset=0开始,char类型占1个字节)。第二个成员d占据8-15字节(double类型占8个字节,对齐系数是8,两者中8较小,所以偏移地址必须是8的倍数,最近的8的倍数是8,所以i从8开始占8个字节,前面的1-7七个字节对齐。)。第三个成员i占据16-19字节(int类型占4个字节,对齐系数是8,两者中4较小,所以偏移地址必须是4的倍数,最近的4的倍数是16,所以i从16开始占4个字节)。而struct Two中最大的数据成员是double型,占8个字节,对齐系数是8,两者中8较小,内存补齐的的地址必须是8 的倍数,而下一个字节是20,不是8的倍数,所以需要内存补齐。最近的8的倍数是24,所以需要再补4位,即占用20-23字节用来结构体内存补齐。所以在#pragma pack(8)情况下,struct Two所需内存为24字节。在32位机器上,下列代码中sizeof(a)的值是()
class A { int i; union U { char buff[13]; int j; }u; void foo(){} typedef char* (*f)(void*); enum{red,green,blue}color; }a; 答案是24=4+13+3+0+0+4。其中成员函数不管是否为空,都不会占用空间,有虚函数除外,有虚函数时会多一个指针(内存+4);typedef是声明,不占用空间;枚举则是int,占4个字节。