一、规则
成员大小就是它的字节数,(sizeof可求)
变量要到偏移量等于它的对齐数的地方才会开始存储
二、实例
(1)无嵌套结构体
i 例一:
解释:
char 的字节大小是1,和VS默认的8相比更小,所以char的对齐数是 1,int 则是4(所有中最大的对齐数是4)
根据规则1,c1存在偏移量为0的地址。用掉第一个字节
接下来要存储 i ,因为他的对齐数是4,根据规则2. 所以浪费了3个字节,来到偏移量为4(4的倍数)的地址开始存储 i ,存储i 用掉了4个字节(从偏移量为4的地方到偏移量为7的地方)。
最后存储 c2,现在是偏移量为8的地址,是1的倍数,所以就在偏移量为8的地方存储了c2,使用1个字节
此时,存储完这3个变量,从 偏移量为1 到 偏移量为8 的地方,一共用了9个字节
根据规则3:结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍,9之后的,最近的4的倍数是12,所以最后又要浪费3个字节,最后结果为12
ii 例二:
解释:
char 的字节大小是1,和VS默认的8相比更小,所以char的对齐数是 1,int 则是4(所有中最大的对齐数是4)
根据规则1,c1存在偏移量为0的地址。用掉第一个字节
接下来要存储 c2,因为他的对齐数是1,根据规则2. 现在偏移量为1(1的倍数)的地址开始存储 c2 ,存储c2用掉了第二个字节。
最后存储 i,现在偏移量为2,不是4的倍数,浪费2个字节,偏移量来到为4的地方,存储用4个字节(从偏移量为4的地方到偏移量为7的地方),用了4个字节。
此时,存储完这3个变量,从 偏移量为0到 偏移量为 7的地方,一共用了8个字节
根据规则3:结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍,8刚好是4的倍数,,最后结果为8
iii 例三
解释:
char 的字节大小是1,和VS默认的8相比更小,所以char的对齐数是 1,int 则是4,double与其相等,对齐数也就是8(所有中最大的对齐数是8)
根据规则1,d 存在偏移量为0的地址。用掉8个字节(从偏移量为0处到偏移量为7处)
接下来要存储 c,因为他的对齐数是1,根据规则2. 现在偏移量为8(是1的倍数).就在此存储 c 用掉了1个字节。
最后存储 i,现在偏移量为9的地址,不是4的倍数,浪费3个字节,所以就在偏移量为12的地方存储了 i。存储用4个字节(从偏移量为12的地方到偏移量为15的地方)
此时,存储完这3个变量,从 偏移量为0到 偏移量为15 的地方,一共用了16个字节
根据规则3:结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍,而16刚好是8的倍数,最后结果为16
(2)有嵌套结构体
例:
解释:
char 的字节大小是1,和VS默认的8相比更小,所以char的对齐数是 1,double则是8,被嵌套的结构体成员⾃⼰的成员中最⼤对⻬数也为8。
则所有中最大的对齐数是 8(含被嵌套结构体中成员的对⻬数)
根据规则1,c1存在偏移量为0的地址。用掉第一个字节
接下来要存储 struct S s,因为他的对齐数是8,
根据规则4(如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处).
现在偏移量为1(不是8的倍数),浪费7个字节,偏移量来到为8的地方的地址开始存储 struct S ,存储用掉了16个字节(从偏移量为8的地方到偏移量为23的地方)
最后存储 d,现在偏移量为24,(是8的倍数),存储用8个字节(从偏移量为24的地方到偏移量为31的地方)
此时,存储完这3个变量,从 偏移量为0到 偏移量为 31的地方,一共用了32个字节
根据规则4: 结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍
,32刚好是8的倍数,,最后结果为32
三、计算结构体相对起始位置的偏移量函数
1.函数介绍
头文件 #include<stddef.h>
返回值:size_t 无符号整形 ( %u 打印无符号数)(这里建议用%zu)
参数:struct Name 结构体名,member Name 成员名
2、实例
#include<stddef.h>
struct S1
{
char s1;
int i;
char c2;
};
struct S2
{
char c1;
char c2;
int i;
};
struct S3
{
double j;
float k;
char m;
};
int main()
{
printf("%zu\n", offsetof(struct S1, s1)); //0
printf("%zu\n", offsetof(struct S1, i)); //4
printf("%zu\n", offsetof(struct S1, c2)); //8
printf("\n");
printf("%zu\n", offsetof(struct S2, c1)); //0
printf("%zu\n", offsetof(struct S2, c2)); //1
printf("%zu\n", offsetof(struct S2, i)); //4
printf("\n");
printf("%zu\n", offsetof(struct S3, j)); //0
printf("%zu\n", offsetof(struct S3, k)); //8
printf("%zu\n", offsetof(struct S3, m)); //12
}
一个变量偏移量是多少,那么就在那个位置的字节数开始存储它
四、修改对齐数
括号里面应该是2的次方(也就是偶数,但还有2的0次方——1)
当括号里是1,就是取消对齐了