结构体
结构体定义:
struct S1
{
char n;
int age;
};
诸如上述,不在多说。
#include <stdio.h>
struct S1
{
char n;
int age;
};
struct S2
{
char n;
int age;
short b;
};
struct student
{
short name[20];
short c ;
int age;
double score;
};
int main()
{
struct S1 s1;
struct S2 s2;
struct student ss;
printf("%p\n",&s1);
printf("%p\n",&s2);
printf("%p\n\n",&ss);
printf("%u\n",sizeof(s1));
printf("%u\n",sizeof(s2));
printf("%u\n\n\n",sizeof(ss));
//这三组的答案
//8
//12
//56
return 0;
}
为什么大小是这样的呢,这是因为有一个对齐数的缘由。
对齐数规则:结构体每个成员的对齐数取编译器的默认对齐数和其字节数较小的一个。
//由于我使用的gcc编译器,无对齐数。所以直接取字节数
地址对齐规则:每一个元素的地址与该结构体的起始地址偏移量必须要是对齐数的整数倍。
printf("%p\n",&s2.n);
printf("%p\n",&s2.age);
printf("%p\n",&s2.b);
你可以这段代码带进去算与其实地址的偏移量(要在同一次程序里面打印出来)
上述两个规则验证之后,存在第三个规则:结构体大小必须是所有成员对齐数最大值的整数倍。
如此就能解释结构体的大小。
S1结构体,无疑是由于int要在偏移量为4个字节处,所以在char之后浪费三个空间,此时结构体的大小是8,恰好是成员对齐数最大值(这里是4)的整数倍。
S2结构体,short b在整形之后,偏移量是4
的倍数也恰好就是2的倍数,所以此时本来大小应该是10,但是由于规则3,所以结构体大小就是12.
student结果也有了,不妨锻炼一下,自己分析。
///
原因的解释。本人相信的以下解释:一般来说,内存都是足够大的,一个整型字节(假如就是4),那么将其存在是4的倍数的地址上,在读取的时候,就只需要扫描是4的倍数的字节,就可以很快的读取到4.相当于快了三倍的速度。想要验证的话,多打印几个整形地址,看下是不是整形字节大小的整数倍。(换下其他类型也行)
也就是为了提升速度,牺牲部分内存。
综合上述原因,再来看结构体对齐原因,结构体本质还是一些类型的组合,所以是一定要使得成员保持地址是整数倍。
那么规则一和规则二就显得很合理,本身就去对齐地址,char对的0004,那么int就是0008才能对齐。
规则三呢?也很简单,内存知道你结构体具体的类型排列吗?不知道,所以就存在一个最大对齐数。
只要有这个对齐数,使得这个结构体的首地址是这个最大对齐数的整数倍,那么就能保证结构体这个各自尽可能地小。所以你才会发现,char地址总是八的倍数,不行你多次编译运行重新试试。
只要结构体地址是最大对齐数的整数倍,结构体内相邻成员无非浪费的就是最大对齐数-1的空间。
///
至此/// ///仅代表个人观点,并无实际的理论,纯经验。仅供参考。
联合体
联合体其实和结构体没什么差别,唯一差别就是所有成员共用内存。
union S3
{
char n;
int age;
}s3;
printf("%u",sizeof(s3));
printf("%p\n\n",&s3.age);
printf("%p\n\n",&s3.n);
可以去程序运行下上述代码结果。
就会知道答案。
由于联合体的这个特性,就可以验证大小端。
s3.n = 10;
printf("%x\n",s3.age);
这段程序加上上面那段,在小端上就是a,大端就会是 0a 00 00 00(十六进制表示的话)
以上便是关于结构体和联合体的一些分享。
希望大家如果看见,感觉有错的话,欢迎在评论区指正。
如果对于你有帮助的话,求赞。谢谢啦