通过更改结构成员声明顺序来减小结构的大小

问题描述 投票:0回答:2

我试图根据它的成员了解结构的大小,如数据对齐的简短教程所述(请参阅here。文章指出“所有数据在结构内自然对齐。如果

type
位于地址 0 下面的
double x
位于地址 8 的偏移量为 8,依此类推。因此,这个结构的大小是 48,即使它只包含 37 个字节的有意义的数据。是的,如果
float m
跟随在
type
之后,m 的偏移量将为 4,结构的大小将减少到 40。”句子

是的,如果 float m 直接跟在 type 之后,m 的偏移量将为 4,结构的大小将减少到 40。

对我来说没有意义。为什么仅仅因为成员的顺序改变了结构大小就减少到 40?是因为

double vy
偏移了 40 个字节,然后填充了额外的 8 个字节,导致结构大小为 48 吗?而如果
float m
直接跟在
type
之后,
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;
}
c optimization struct memory-alignment
2个回答
1
投票

有了原始的字节序,我们需要:

  • 一个字节代表
    char type
    .
  • 七个字节使以下
    double
    对齐到八个字节的倍数。
  • 16字节,
    x
    y
    各8个字节,
    double x,y
    .
  • 四个字节代表
    float m
    .
  • 四个字节使以下
    float
    对齐到八个字节的倍数。
  • 16字节,
    vx
    vy
    各8个字节,
    double vx,vy
    .

即1+7+16+4+4+16 = 48字节。

随着

float
的移动,我们需要:

  • 一个字节代表
    char type
    .
  • 三个字节使后面的
    float
    对齐到四个字节的倍数。
  • 四个字节代表
    float m
    .
  • 16字节,
    x
    y
    各8个字节,
    double x,y
    .
  • 16字节,
    vx
    vy
    各8个字节,
    double vx,vy
    .

即 1 + 3 + 4 + 16 + 16 = 40 字节。

观察到

float
double
之间不需要字节,因为
float
以八字节的倍数结束。


0
投票

你要找的答案实际上在你链接的文章中提到了:

例如,如果用于标识它的地址与八 (8) 对齐,则自然对齐一个 8 字节的浮点数据

如果

type
是第二个成员,该结构已经占用了1个字节,所以下一个可用于自然对齐的位置是下一个八的倍数。为了自然对齐,您实际上跳过了 7 个字节,这可以适合整个浮点数。由于
float m
只需要4个字节,所以可以在
type
x
之间自然对齐。

© www.soinside.com 2019 - 2024. All rights reserved.