使用sizeof()计算结构体大小
下面代码的输出结果是:
#include <iostream>
using namespace std;
#pragma pack(4)
struct T{
char a;
short b;
char c;
};
#pragma pack()
int main()
{
cout << sizeof(T) << endl;
return 0;
}
A. 4 B. 5 C. 8 D. 6
一、sizeof()计算结构体大小
结构体成员按照定义时的顺序依次存储在连续的内存空间,但是结构体的大小并不是简单的把所有成员大小相加,而是遵循一定的规则,需要考虑到系统在存储结构体变量时的地址对齐问题。
- 结构体变量中成员的偏移量必须是成员大小的整数倍 (0是任何数的整数倍)
- 结构体大小必须是所有成员大小的整数倍 (即所有成员大小的公倍数)
- 结构体大小计算方式:最后一个成员的偏移量加上其大小。
例1:
struct T{
char a;
short b;
char c;
};
【分析】
第一个成员char a的偏移量为0;
第二个成员short b的偏移量为前一个成员的偏移量+前一个成员的大小,即0 + 1 = 1,因1不是该成员大小2的整数倍,所以需要调整到2(最小倍数),所以第二个成员的偏移量为2;
第三个成员char c的偏移量为第二个成员的偏移量+第二成员的大小2 + 2 = 4, 4是其大小1的整数倍,所以第三个成员的偏移量为4;
所以该结构体大小sizeof(T)的计算结果为最后一个成员的偏移量加上其大小即4 + 1 = 5,但5不是所有成员大小(1, 2, 1)的整数倍,所以需要补齐到6。
注:偏移量可以理解为结构体成员相对于结构体的起始地址
例2:嵌套的结构体
struct T
{
short a;
struct
{
char b;
int c;
} tmp;
int d;
};
对于嵌套的结构体,应该将其展开,规则变化为:
- tmp结构体的第一个成员的偏移量(代表tmp结构体在整个结构体中的起始地址)应当是tmp结构中最大成员大小的整数倍;
- 其它成员的偏移量计算方法不变
- 结构体大小sizeof(T)必须是展开后所有成员大小的整数倍
【分析】
第一个成员short a的偏移量为0;
第二个成员char b, 其偏移量本是前一个成员的偏移量+前一个成员的大小, 即0 + 2 = 2,但它又是tmp结构体的第一个成员,其偏移量应该是tmp结构体中最大成员int c大小4的整数倍, 所以应该调整到4;
第三个成员int c,偏移量为4 + 1 = 5,调整到其自身大小整数倍8;
第四个成员int d,偏移量为8 + 4 = 12,已经是自身大小整数倍,无需调整;
所以该结构体大小sizeof(T)的计算结果为最后一个成员的偏移量加上其大小即12 + 4 = 16,16是展开后所有成员大小(2, 1, 4, 4)的整数倍,所以无需再调整。
例3:包含数组成员的结构体
struct T
{
float f;
char p;
int arr[3];
};
将数组看成一个结构体,其中所有成员均为该数组类型变量,同样展开计算。
【分析】
第一个成员float f偏移量为0;
第二个成员char p偏移量为0 + 4 = 4,是其大小1的整数倍,无需调整;
第三个成员int arr[3]为数组,展开为三个int类型成员计算
…
最后一个成员的偏移量为16
所以该结构体大小sizeof(T)的计算结果为最后一个成员的偏移量加上其大小即16 + 4 = 20,20是展开后所有成员大小(4, 1, 4)的整数倍,所以无需再调整。
二、#pragma pack(n)
编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:
- 如果
n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式 - 如果
n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。
结构的总大小也有个约束条件,分下面两种情况:
- 如果
n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数; - 否则必须为
n的倍数。
总结一下,就是两条判断原则:
-
每个成员的偏移量必须是
x的倍数,x = min(n,该成员大小) -
结构体的总大小必须是
y的倍数,y = min(n,占用空间大的变量的字节数)
例:
#pragma pack(4)
struct T{
char a;
short b;
char c;
};
#pragma pack()
【分析】
n = 4;
第一个成员char a,其偏移量为0(无论n的值和第一个成员的类型,第一个成员的偏移量总是0);
第二个成员short b, 计算x = min(4, 2) = 2,其偏移量为第一个成员的偏移量+第一个成员的大小,即0 + 1 = 1,因为1不是x的倍数,所以偏移量调整为2;
第三个成员char c,计算x = min(4, 1) = 1的偏移量为第二个成员的偏移量+第二成员的大小,即2 + 2 = 4, 4是x的整数倍,所以第三个成员的偏移量为4;
计算y = min(4, max(1, 2, 1)) = 2, 该结构体大小sizeof(T)的计算结果为最后一个成员的偏移量加上其大小即4 + 1 = 5,但5不是y的整数倍,所以需要补齐到6。
三、总结
- 计算每个成员的偏移量:第一个成员偏移量总是0;其它成员偏移量=前一个成员偏移量+前一个成员大小, 然后根据规则调整;
- 计算结构体大小 = 最后一个成员偏移量 + 最后一个成员大小;再根据规则调整。
- 标注#pragma pack(n)和不标注的规则不一样, 嵌套结构体(或者带数组成员的结构体)的规则也发生变化。
更多推荐


所有评论(0)