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

ncgqoxb0  于 2023-03-28  发布在  其他
关注(0)|答案(2)|浏览(100)

我正试图根据结构的成员来理解结构的大小,正如一个关于数据对齐的简短教程所描述的那样(参见here。该文章指出“所有数据在结构中自然对齐。如果type位于地址0,则以下double x位于地址8的偏移量8,依此类推。因此,即使这个结构只包含37字节的有意义数据,它的大小也是48。是的,如果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;
}
ibrsph3r

ibrsph3r1#

使用原始字节顺序,我们需要:

  • char type的一个字节。
  • 7个字节,使以下double与8个字节的倍数对齐。
  • 16个字节,double x,y中的xy各8个字节。
  • float m的四个字节。
  • 四个字节,使下面的float与八个字节的倍数对齐。
  • 16个字节,double vx,vy中的vxvy各8个字节。

即1+7+16+4+4+16 = 48字节。
移动float后,我们需要:

  • char type的一个字节。
  • 三个字节,使以下float与四个字节的倍数对齐。
  • float m的四个字节。
  • 16个字节,double x,y中的xy各8个。
  • 16个字节,double vx,vy中的vxvy各8个字节。

即1 + 3 + 4 + 16 + 16 = 40字节。
注意,floatdouble之间不需要字节,因为float以8字节的倍数结束。

sdnqo3pr

sdnqo3pr2#

你要找的答案实际上在你链接的文章中提到了:
例如,如果用于标识8字节浮点数据的地址与八(8)对齐,则该数据自然对齐
如果type是第二个成员,则结构体已经占用了1个字节,因此下一个可用于自然对齐的位置是下一个8的倍数。为了自然对齐,您实际上跳过了7个字节,这可以容纳整个浮点数。由于float m只需要4个字节,因此它可以在typex之间自然对齐。

相关问题