结构体对(对齐)计算

我们实际生活中,保存的数据一般不会是同一种类型,所以引入了结构体。而结构体的大小也不是成员类型大小的简单相加。需要考虑到系统在存储结构体变量时的地址对齐问题。

由于存储变量地址对齐的问题,结构体大小计算必须满足两条原则:

一、结构体成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)

二、结构体大小必须是所有成员大小的整数倍

下面来具体分析
1、简单结构体

struct s1{
    
    
char ch1;
char ch2;
int i;
};

这个结构体的大小容易计算,满足两个原则即可,为8,那么下面这个呢

struct s2{
    
    
char ch1;
int i;
char ch2;
};

这个结构体大小是12,为什么呢?仔细看看两个原则,要满足偏移量是成员的整数倍,ch1偏移量是0,i的偏移量不可能是1,因为1不是i大小4的倍数,所以i的偏移量是4,ch2的偏移量就变为了8,所以满足结构体大小是成员大小整数倍,就是12。
2、成员包含数组的结构体

struct s3{
    
    
char ch;
int i;
char str[10];
};

这个结构体的大小是20,先看前两个成员,大小是8,毋庸置疑,这个char类型的数组,只需要把它看做10个char连在一起即可,加起来就是18,再满足结构体大小为成员整数倍,所以大小就是20。

3、成员包含结构体的结构体

(1)
struct s4{
    
    
char ch;
int i;

struct s{
    
    
char ch1;
int j;
}a;

float f;
};

里面这个结构体s的大小是8,那么是否结构体s4大小就要向8对齐呢?这个结构体s4的大小是20,很明显不是8的倍数。所以计算结构体s4大小时是把里面这个结构体s就看做是一个char,和一个int,不是看做一个整体。

struct s4{
    
    
char ch;
int i;

struct s{
    
    
char ch1;
int j;
};

float f;
};

这个要和上面做区分,这个结构体s4的大小为12,因为里面的结构体只是起定义一个数据类型的作用,而没有声明变量,所以不占内存空间,并且不能单独拿出里面这个结构体来声明一个变量(如s a;)也不能通过声明外围结构体变量用点运算符进行声明(如s4 a; a.s b;),所以里面这个结构体是实际意义的。

4、成员包含联合体的结构体

struct s5{
    
    
char ch;
int i;

union p{
    
    
char ch1;
int j;
}a;

};

联合体大小就是成员中最大类型的大小,所以这个结构体大小是12.

(2)
struct s5{
    
    
char ch;
int i;

union p{
    
    
char ch1;
int j;
};

};

这个结构体大小为8,和4.(2)的道理一样。
5、指定对齐值

1)对齐值小于最大类型成员值

#pragma pack(4) //指定向4对齐 最大是8

struct s6{
    
    
char ch;

int i;

float f;

double d;

};

如果我们没有指定对齐值,这个结构体大小是24,我们指定向4对齐,所以大小是4的倍数,所以结构体大小是20。

2)对齐值大于最大类型成员值

#pragma pack(10)

struct s7{
    
    
char ch;

int i;

float f;

double d;

};

我们指定的对齐值是10,最大为8,是否就向10对齐?不是,当指定对齐值大于自身对齐值时,向自身对其值对齐,大小是24.

总的来说,向指定对齐值和自身对齐值中较小的那个值对齐。

猜你喜欢

转载自blog.csdn.net/weixin_48321071/article/details/124733856