本文共 1497 字,大约阅读时间需要 4 分钟。
原本以为结构体的大小就是里边各个成员变量的大小总和,但是运行结构并不是这样,原来结构体大小计算还有一个规则——内存对齐
1.第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 从零偏移处开始,按字节大小计算,判断此偏移地址是否为该成员变量和对齐参数两者之间的最小值,若是,则从此处开始占用内存,大小为该类型所占字节数值,若不是,则内存向后偏移到最小值整数倍处,再开始占用空间。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。 4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所最大对齐数(含嵌套结构体的对齐数)的整数倍。举个栗子:
struct S1{ char c1; int i; char c2;};
这里就不加运行结果的图片了,结果是 12 。因为我用的是 VS,所以默认对齐数为 4,第一个 c1 的大小是1,所以对齐数为 1,第二个 i 的大小为 4,所以对齐数是 4,与前边的 c1 对齐,则 c1 要再向后偏移 3 个字节,成为 4 个字节才能对齐,最后一个 c2 的大小是 1 ,对齐数也就是 1 ,加在一起就是 4+4+1 = 9,因为还有一个规则是结构体总大小要是最大对齐数的整数倍,现在的最大对齐数是 4 ,要是 4 的整数倍,则需要再补上 3 个字节总大小就是 12 个字节,也就是最大对齐数(4)的整数倍了。
再举个栗子
struct S2{ char c1; char c2; int i;};
这个结果是 8,因为 c1 和 c2 的对齐数为1,对齐玩=完之后偏移量为 2 ,2 不是 4 的整数倍,所以再往后偏移两位,偏移量为 4 的时候,可以与 i 对齐,与 i 对齐之后,偏移量为 8,也是最大对齐数(4)的整数倍,所以最后结果为 8。
看一个结构体对齐的
struct S1{ double d; char c; int i;};struct S2 { char c1; struct S1 s1; double d;};int main() { printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); return 0;}首先,S1 的大小是 16,d 的大小是 8 ,d 对齐后偏移量为 8,是 1 的倍数,所以 c 对齐后是偏移量是 9 ,9 不是 4 的倍数,偏移到 12是 4 的倍数,再加上 i 结果就是 16 个字节。 S2 的大小,首先 c1 大小是 1,偏移量也即是 1 ,然后对齐结构体 S1,结构体要对齐它的最大对齐数的整数倍(即结构体的大小16),对齐之后偏移量为 18,不是后边 d 的整数倍,直到偏移量为 24 ,d 可以对齐,对齐之后结果为 32 。
当然,默认对齐数是可以改变的。#pragma pack(n) 这个指令就可以改变默认对齐数,n 是要改变的值。
为什么结构体要对齐?
这是一种以空间换时间的做法,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器 需要作两次内存访问;而对齐的内存访问仅需要一次访问修改默认对齐数
使用 #pragma pack(n) n 是多少 就是设置对齐数为多少转载地址:http://eqwzi.baihongyu.com/