sizeof求结构体大小问题详解
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
[cpp] view plain copy
1. 2. 3. 4. 5. 6.
struct stu1 { int i; char c; int j; };
用 sizeof 求该结构体的大小,发现值为 12。int 占 4 个字节,char 占 1 个字节, 结果应该是 9 个字节才对啊, 为什么呢? 先介绍一个相关的概念——偏移量。偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体 大小等于最后一个成员的偏移量加上最后一个成员的大小。显然,结构体变量中第一个成员的地址就是结构体变量 的首地址。因此,第一个成员 i 的偏移量为 0。第二个成员 c 的偏移量是第一个成员的偏移量加上第一个成员的大 小(0+4),其值为 4;第三个成员 j 的偏移量是第二个成员的偏移量加上第二个成员的大小(4+1),其值为 5。
其值为 20。float 占 4 个字节,到 char p 时偏移量为 4,p 占一个字节,到 int adf[3]时偏移量为 5,扩展为 int 的整数倍,而非 int adf[3]的整数倍,这样偏移量变为 8,而不是 12。结果是 8+12=20,是最大成员 float 或 int 的 大小的整数倍。 如何给结构体变量分配空间由编译器决定,以上情况针对的是 Linux 下的 GCC。在 Windows 下的 VC 平台 也是这样,至于其他平台,可能会有不同的处理。
13. 14.
}
char f;
结构体 ss 单独计算占用空间为 8,而 stu5 的 sizeof 则是 20,不是 8 的整数倍,这说明在计算 sizeof(stu5) 时,将嵌套的结构体 ss 展开了,这样 stu5 中最大的成员为 ss.j,占用 4 个字节,20 为 4 的整数倍。如果将 ss 当 做一个整体,结果应该是 24 了。
结构体 stu5 的成员 ss.c 的偏移量应该是 4,而不是 2。整个结构体大小应该是 16。
下述代码测试原则 2:
[cpp] view plain copy
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
struct stu5 { char i; struct { char c; int j; } ss; char a; char b; char d; char e;
[cpp] view plain copy
1. 2. 3. 4. 5.
struct stu2 { int k; short t; };
成员 k 的偏移量为 0;成员 t 的偏移量为 4,都不需要调整。但计算出来的大小为 6,显然不是成员 k 大小的 整数倍。因此,编译器会在成员 t 后面补上 2 个字节,使得结构体的大小变成 8 从而满足第二个要求。 由此可见,结构体类型需要考虑到字节对齐的情况,不同的顺序会影响结构体的大小。
另一个特殊的例子是结构体中包含数组,其 sizeof 应当和处理嵌套结构体一样,将其展开,如下例子:
[cpp] view plain copy
1. 2. 3. 4. 5. 6. 7.
struct ss { float f; char p; int adf[3]; }; cout<<sizeof(ss)<<endl;
对比下面两种定义顺序:
[cpp] view plain copy
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
struct stu3 { char c1; int i; char c2; } struct stu4 { char c1; char c2; int i; }
虽然结构体 stu3 和 stu4 中成员都一样,但 sizeof(struct stu3)的值为 12 而 sizeof(struct stu4)的值为 8。 对于嵌套的结构体,需要将其展开。对结构体求 sizeof 时,上述两种原则变为:
(1)展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。
然而,在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:
(1)结构体变量中成员的偏移量必须是成员大小的整数倍(0 被认为是任何数的整数倍)
(2)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。
上面的例子中前两个成员的偏移量都满足要求,但第三个成员的偏移量为 5,并不是自身(int)大小的整数倍。 编译器在处理时会在第二个成员后面补上 3 个空字节,使得第三个成员的偏移量变成 8。结构体大小等于最后一个 成员的偏移量加上其大小,上面的例子中计算出来的大小为 12,满足要求。 再来看另外一个例子:
(2)结构体大小必须是所有成员大小的整数倍,这里所有成员计算的是展开后的成员,而不是将嵌套的结构
体当做一个整体。
看下面的例子:
[cpp] view plain co来自百度文库y
1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
struct stu5 { short i; struct { char c; int j; } ss; int k; }
运算符 sizeof 可以计算出给定类型的大小,对于 32 位系统来说,sizeof(char) = 1; sizeof(int) = 4。基本数据类 型的大小很好计算,我们来看一下如何计算构造数据类型的大小。
C 语言中的构造数据类型有三种:数组、结构体和共用体。
数组是相同类型的元素的集合,只要会计算单个元素的大小,整个数组所占空间等于基础元素大小乘上元素 的个数。 结构体中的成员可以是不同的数据类型,成员按照定义时的顺序依次存储在连续的内存空间。和数组不一样 的是,结构体的大小不是所有成员大小简单的相加,需要考虑到系统在存储结构体变量时的地址对齐问题。看下面 这样的一个结构体:
1. 2. 3. 4. 5. 6.
struct stu1 { int i; char c; int j; };
用 sizeof 求该结构体的大小,发现值为 12。int 占 4 个字节,char 占 1 个字节, 结果应该是 9 个字节才对啊, 为什么呢? 先介绍一个相关的概念——偏移量。偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体 大小等于最后一个成员的偏移量加上最后一个成员的大小。显然,结构体变量中第一个成员的地址就是结构体变量 的首地址。因此,第一个成员 i 的偏移量为 0。第二个成员 c 的偏移量是第一个成员的偏移量加上第一个成员的大 小(0+4),其值为 4;第三个成员 j 的偏移量是第二个成员的偏移量加上第二个成员的大小(4+1),其值为 5。
其值为 20。float 占 4 个字节,到 char p 时偏移量为 4,p 占一个字节,到 int adf[3]时偏移量为 5,扩展为 int 的整数倍,而非 int adf[3]的整数倍,这样偏移量变为 8,而不是 12。结果是 8+12=20,是最大成员 float 或 int 的 大小的整数倍。 如何给结构体变量分配空间由编译器决定,以上情况针对的是 Linux 下的 GCC。在 Windows 下的 VC 平台 也是这样,至于其他平台,可能会有不同的处理。
13. 14.
}
char f;
结构体 ss 单独计算占用空间为 8,而 stu5 的 sizeof 则是 20,不是 8 的整数倍,这说明在计算 sizeof(stu5) 时,将嵌套的结构体 ss 展开了,这样 stu5 中最大的成员为 ss.j,占用 4 个字节,20 为 4 的整数倍。如果将 ss 当 做一个整体,结果应该是 24 了。
结构体 stu5 的成员 ss.c 的偏移量应该是 4,而不是 2。整个结构体大小应该是 16。
下述代码测试原则 2:
[cpp] view plain copy
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
struct stu5 { char i; struct { char c; int j; } ss; char a; char b; char d; char e;
[cpp] view plain copy
1. 2. 3. 4. 5.
struct stu2 { int k; short t; };
成员 k 的偏移量为 0;成员 t 的偏移量为 4,都不需要调整。但计算出来的大小为 6,显然不是成员 k 大小的 整数倍。因此,编译器会在成员 t 后面补上 2 个字节,使得结构体的大小变成 8 从而满足第二个要求。 由此可见,结构体类型需要考虑到字节对齐的情况,不同的顺序会影响结构体的大小。
另一个特殊的例子是结构体中包含数组,其 sizeof 应当和处理嵌套结构体一样,将其展开,如下例子:
[cpp] view plain copy
1. 2. 3. 4. 5. 6. 7.
struct ss { float f; char p; int adf[3]; }; cout<<sizeof(ss)<<endl;
对比下面两种定义顺序:
[cpp] view plain copy
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
struct stu3 { char c1; int i; char c2; } struct stu4 { char c1; char c2; int i; }
虽然结构体 stu3 和 stu4 中成员都一样,但 sizeof(struct stu3)的值为 12 而 sizeof(struct stu4)的值为 8。 对于嵌套的结构体,需要将其展开。对结构体求 sizeof 时,上述两种原则变为:
(1)展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。
然而,在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:
(1)结构体变量中成员的偏移量必须是成员大小的整数倍(0 被认为是任何数的整数倍)
(2)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。
上面的例子中前两个成员的偏移量都满足要求,但第三个成员的偏移量为 5,并不是自身(int)大小的整数倍。 编译器在处理时会在第二个成员后面补上 3 个空字节,使得第三个成员的偏移量变成 8。结构体大小等于最后一个 成员的偏移量加上其大小,上面的例子中计算出来的大小为 12,满足要求。 再来看另外一个例子:
(2)结构体大小必须是所有成员大小的整数倍,这里所有成员计算的是展开后的成员,而不是将嵌套的结构
体当做一个整体。
看下面的例子:
[cpp] view plain co来自百度文库y
1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
struct stu5 { short i; struct { char c; int j; } ss; int k; }
运算符 sizeof 可以计算出给定类型的大小,对于 32 位系统来说,sizeof(char) = 1; sizeof(int) = 4。基本数据类 型的大小很好计算,我们来看一下如何计算构造数据类型的大小。
C 语言中的构造数据类型有三种:数组、结构体和共用体。
数组是相同类型的元素的集合,只要会计算单个元素的大小,整个数组所占空间等于基础元素大小乘上元素 的个数。 结构体中的成员可以是不同的数据类型,成员按照定义时的顺序依次存储在连续的内存空间。和数组不一样 的是,结构体的大小不是所有成员大小简单的相加,需要考虑到系统在存储结构体变量时的地址对齐问题。看下面 这样的一个结构体: