关于调整结构体成员顺序缩减结构体大小的原理疑问
结构体成员顺序对内存对齐与大小的影响
我正在学习数据对齐相关内容,了解结构体成员顺序对结构体大小的影响。相关内容提到:
结构体内部所有数据均自然对齐。若type位于地址0,后续的double x将位于偏移量8的地址8处,依此类推。因此该结构体大小为48字节,尽管仅包含37字节有效数据。并且,若float m紧跟在type之后,m的偏移量将为4,结构体大小会缩减至40字节。
我有个疑问:为什么仅仅改变成员顺序就能把结构体大小从48字节缩减到40字节?是不是因为原顺序中double vy的偏移量是40,之后需要额外填充8字节让结构体大小满足对齐要求到48;而调整顺序后double vy的偏移量是32,填充8字节后大小就到40了?
我编写了一个C程序验证结构体成员的对齐情况:
/*Outputs: particle one alignment: type 0 x 8 y 16 m 24 vx 32 vy 40 struct size --> 48 particle two alignment: type 0 m 4 x 8 y 16 vx 24 vy 32 struct size --> 40 */ #include <stdio.h> #include <stdlib.h> typedef struct ParticleOne { char type; double x,y; float m; // after `y` member double vx, vy; } ParticleOne; typedef struct ParticleTwo { char type; float m; // after `type` member double x,y; double vx, vy; } ParticleTwo; int main() { ParticleOne *particle_one = malloc(sizeof(ParticleOne)); ParticleTwo *particle_two = malloc(sizeof(ParticleTwo)); // Particle one alignment/offset information void *p1_type = &particle_one->type; void *p1_x = (void*)&particle_one->x - p1_type; void *p1_y = (void*)&particle_one->y - p1_type; void *p1_m = (void*)&particle_one->m - p1_type; void *p1_vx = (void*)&particle_one->vx - p1_type; void *p1_vy = (void*)&particle_one->vy - p1_type; printf("particle one alignment:\n"); printf("type %d\n", p1_type - p1_type); printf("x %d\n", p1_x); printf("y %d\n", p1_y); printf("m %d\n", p1_m); printf("vx %d\n", p1_vx); printf("vy %d\n", p1_vy); printf("struct size --> %d\n", sizeof(ParticleOne)); // Particle two alignment/offset information void *p2_type = &particle_two->type; void *p2_x = (void*)&particle_two->x - p2_type; void *p2_y = (void*)&particle_two->y - p2_type; void *p2_m = (void*)&particle_two->m - p2_type; void *p2_vx = (void*)&particle_two->vx - p2_type; void *p2_vy = (void*)&particle_two->vy - p2_type; printf("particle two alignment:\n"); printf("type %d\n", p2_type - p2_type); printf("m %d\n", p2_m); printf("x %d\n", p2_x); printf("y %d\n", p2_y); printf("vx %d\n", p2_vx); printf("vy %d\n", p2_vy); printf("struct size --> %d\n", sizeof(ParticleTwo)); return 0; }
你的猜测完全正确,核心原因就是内存对齐规则:
- 结构体的每个成员都要满足自身的自然对齐要求:
char占1字节(无需额外对齐),float占4字节(需对齐到4字节边界),double占8字节(需对齐到8字节边界)。 - 结构体整体的大小必须是其最大成员对齐字节数的整数倍(这里最大成员是
double,即8字节)。
原结构体(ParticleOne)的内存布局:
char type:占0-0字节,之后需要填充7字节(因为下一个成员double x要对齐到8字节边界),所以x从8字节开始。double x:8-15字节;double y:16-23字节。float m:24-27字节(占4字节),之后需要填充4字节(下一个成员double vx要对齐到8字节边界),所以vx从32字节开始。double vx:32-39字节;double vy:40-47字节。- 结构体整体大小是48字节,正好是8的整数倍,无需额外填充。
调整顺序后的结构体(ParticleTwo)的内存布局:
char type:0-0字节,之后填充3字节(下一个成员float m要对齐到4字节边界),m从4字节开始。float m:4-7字节,下一个成员double x要对齐到8字节边界,刚好从8字节开始,无需填充。double x:8-15字节;double y:16-23字节;double vx:24-31字节;double vy:32-39字节。- 结构体整体大小是40字节,正好是8的整数倍,无需额外填充。
简单来说,调整顺序后,把小尺寸的float m放在char type后面,利用了type后面的填充空间(原本要填7字节,现在填3字节给m用),避免了后续double成员前的额外填充,最终减少了整体的内存占用。
内容的提问来源于Stack Exchange,提问作者Jared
相关产品推荐
相关产品推荐

