C语言提供了许多内置类型,如:char、int、double等,假设我想描述一本书,这时单一的内置类型是不行的。因为要描述一本书需要作者、定价等。所以C语言为我们提供了结构体这种自定义的数据类型。下面我来介绍一下结构体。
目录
结构体类型的声明
结构体其实就是一些值的集合,这些值被称为成员变量。结构体的每个成员可以是不同类型的变量。
结构体的语法定义如下:
- struct是结构体的关键字
- tag:是结构体名
- member-list:是成员列表
- variable-list:是变量列表(这里可以不创建变量)
- 最后的;不要忘了
结构体变量的创建和初始化
变量创建:
初始化时要按照结构体成员的顺序来进行初始化(其实也可以不按照顺序这个以后再说):
结构成员访问操作符
如果是结构体变量用点操作符(.),如果是指向结构体的指针用(->)。
在上面我说了初始化也可以不按照结构体成员的顺序来初始化那要怎么写呢?
结构体内存对齐*
结构体的大小并不是成员一共有多大它就多大,它有着自己的一套规则。
- 1. 第一个成员在与结构体变量偏移量为0的地址处。
- 2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数与该成员变量大小的较小值。
- VS 中默认的值为 8。
- Linux中 gcc 没有默认对齐数,对齐数就是成员自身的大小。
- 3. 结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 4. 如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
我来给大家举个栗子,方便大家理解(我用的是VS)。
蓝背景→(最大)对齐数
红背景→与结构体首地址的偏移量
a是char类型占1个字节。因为a是第一个成员,所以a存在结构体地址的首位(第一个成员不用对齐,但有对齐数)。
b是int类型占4个字节小于VS规定的8个字节,故对齐数是4个字节。因为1不是4的整数倍所以向后找,因为4是4的整数倍,所以在4处开始存。
c是char类型占1个字节小于VS规定的8个字节,故对齐数是1个字节。因为8是1的整数倍,所以在8处开始存。
在这3个中最大对齐数是4个字节,因为9不是4的整数倍所以向后找,因为12是4的整数倍,所以总大小是12个字节。
图例如下↓
那如果是嵌套的结构体该怎么算呢?其实也大差不差。
前面的我就不过多赘述了。
当走到struct S2时,struct S2中最大对齐数是4个字节,因为1不是4的整数倍所以向后找,因为4是4的整数倍,所以在4处开始存放struct S2的第一个成员,其它和之前一样。
在确定结构体总大小时,要看所有对齐数,并找到最大的对齐数。在这个中最大对齐数是4个字节,因为16是4的整数倍,所以总大小的16个字节。
图例如下↓
给大家出一道题:
#include <stdio.h>
struct S
{
char a;
char b;
int c;
};
int main()
{
printf("%zd", sizeof(struct S));
return 0;
}
因为a,b都占1个字节故顺着存,2不是4的整数倍所以向后找,遇到4时开始存。因为最大对齐数是4个字节,且8是4的整数倍,故结构体总大小是8个字节。
怎么样写对了吗?
我举的第一个栗子和这个练习相比不难发现数据是一样的只是顺序不同,但是结构体的大小居然不同!
事实上,如果同一类型的数据放在一起就可能会减少内存。
为什么要存在内存对齐呢?事实上这是牺牲空间换时间的做法。
好了讲到这儿就差不多讲完了,希望你能有所收获。如果存在错误地方请及时指出,如果还有什么不懂的地方可以私信我,如果觉得不错那就点点赞吧!