-
这是个好问题!
为什么对齐有问题? 简单来说,就是提高存取内存的效率,这与CPU的内部机制有关,想要深入了解,就需要阅读Intel开发者手册。 对齐采用的总体原则如下:
4 字节变量的存储应与可被 4 整除的地址对齐,而 8 字节变量的存储应与可被 8 整除的地址对齐。 其他变量可以通过类比来推断。 如果未对齐,编译器会将变量的存储延迟几个字节,以确保其对齐。
猫的位置是地址 0 - 地址 3
a 数组的位置是地址 4 - 地址 23
存放狗的位置是地址 24 到地址 31
在这里你可以看到它们都遵循对齐原则(即,每个变量开始的地址可以除以它占用的字节数),所以它是 32
第二种情况是这样的:
猫仍然存储在地址 0 - 地址 3。
a 的数组是地址 4 到地址 27。
在存储 dog 时,编译器计算出将下一个地址除以 28 不会将 double 的字节数除以 8,因此它会递增地址。 29,30,31 仍然不能除 8,知道 8 递增到 32 时可以被除法,所以 dog 变量将存储在地址 32 到地址 39,从地址 0 到地址 39 正好是 40 个字节,这解释了第二种情况。
ps.事实上,你的问题还有另一种变体,那就是结构中的结构,这将涉及内部结构对齐的问题。 以后你见到你的时候问我问题,我会向你解释的。
-
结构数据是 8 字节对齐的。
int cat; 4
int a[5]; 4*5 =20
double dog; 8
大小是 32,而 32 正好是 8 的倍数。
结构数据 8 字节对齐。
int cat; 4
int a[6]; 4*6=24
double dog;8、尺寸为40
如果你谈论数据对齐,你可能无法想象。
因此,您只需记住,真实大小必须由与该数字的倍数对齐的字节组成。
例如,第二个是真实的,是 36,它是 8 的倍数,大于 36,最近的一个是 40,所以我要试着画一个。
-
您可以在设置项目的地方设置几个字节的对齐方式,结果会因设置而异。
默认情况下,它由 8 个字节对齐,sizeof(int)=4, sizeof(double)=8,因此结构体的大小将为 40
按 4 个字节对齐,结构大小为 32
-
对齐与数据在内存中的位置有关。 如果变量的内存地址恰好是其长度的整数倍,则称为自然对齐。 例如,在 32 位 CPU 中,假设整数变量的地址是0x00000004,那么它是自然对齐的。
需要字节对齐的根本原因是 CPU 访问数据的效率。 假设上述整数变量的地址不是自然对齐的,例如,对于0x00000002,如果 CPU 获取其值,则需要访问内存两次,第一次从 0x00000002-0x00000003 中获取短路,第二次从 0x00000004-0x00000005 获取短路,然后将其组合以获得所需的数据, 如果变量在0x00000003地址上,则需要访问内存三次。第一次是char,第二次是short,第三次是char,然后得到整数数据。如果变量处于自然对齐的位置,则可以在一次尝试中检索一次数据。
某些系统具有非常严格的对齐要求,例如 SPARC 系统,在获取未对齐的数据时会出现错误,例如:
char ch[8];
char *p = &ch[1];
int i = *(int *)p;
在运行时报告段错误,而在 x86 上没有错误,只是效率降低。
-
成员大小之和不等于类的大小,主要是因为类内部有填充。 额外的填充保证了在声明阵列时仍将满足各个元素的对齐要求,并且 CPU 将满足不同类型的对齐要求。 X86 一般可以访问未对齐的数据,但效率较低,部分 CPU 无法访问未对齐的数据,会导致异常。
假设是 32 位系统,通用数据类型的对齐要求是 char 1 字节。
短 2 个字节。
int 4 字节。
长 4 个字节。
float 4 字节。
双 8 字节(不一定,在 Linux 上似乎只需要 4 个字节)。
看完你的**后,每个成员的偏移量是。
index - 0
name - 4
age - 30
salary - 32
这里的总尺寸是 40,理由是年龄不是从 29 岁开始,而是从 30 岁开始,以确保满足短裤的对齐要求。
-
结构体内存对齐的原则(在没有杂注包宏的情况下):
原则 1:数据成员对齐规则:结构的第一个数据成员(结构或联合并集)放置在 0 的偏移量处,并且每个数据成员的起始位置应从成员大小的整数倍存储(例如,如果 int 在 32 位计算机中为 4 个字节, 它应该从整数倍地址 4) 存储。
原则 2:结构体作为成员:如果结构中有一些结构体成员,则结构体成员应从其中最大元素大小的整数倍存储。 (struct a 有结构 b,b 有 char、int、double 等,那么 b 应该从 8 的整数倍存储。
原则3:精加工工作:结构的总尺寸,即尺寸的结果,必须是其内部最大杆件的整数倍,并且必须弥补不足。
让我们自己检查一下。
-
4 + 25 +1 (30 可以被后面的 2 整除) +2 +8 = 40 (可以被 8 整除,但不能整除,但必须加)。
从**本身和运行情况来看,可执行程序的内容与粘贴的**不匹配(可能是修改后没有重新编译,而修改前的**运行,否则不会**现在出现可以编译传递的错误,例如第二行末尾有更多的“op”, 和“现有1人捐款无产出”),修改建议如图所示: