结构体相信大家都不陌生了,这里我简单介绍一下它的定义。
结构体定义
struct S
{
int a;
char c;
}s1;
这里面struct S就是它的名字,s1是它的变量名。可以近似理解成struct S就相当于int,s1就相当于i。这样可能更好理解。这就是结构体的定义,可能有些读者会有疑惑,我平时看书上不是这么写的,书上写的形式应该是这样的:
typedef struct S
{
int a;
char c;
}s1;s2;
这个时候这里的s1和s2又分别是什么意思呢,注意这个时候s1不再是变量名了,因为struct前面加了个typedef,这个意思是把struct S给重命名为s1,而s2才是它的变量名。还有一种写法就是把s1放到struct S后面,就像这样:
typedef struct S s1
{
int a;
char c;
}s2;
这样子也是可以的。
结构体初始化
结构体初始化挺好理解的,只要你明白了我上面所说的把它类比成你平常用的类型初始化就行了,唯一一点不同的,就是在结构体初始化中,顺序需要对齐你在定义中的类型数据的顺序。
还是老样子,要是不理解为什么这样做的话,就把struct S想象成int或者其他数据类型都可以,s1就是变量名,仅此而已。后面的初始化需要注意的就是对齐你定义中的数据类型就行了。打印的时候可以看到是用s1.a去找到数据的,这里的.就是用来访问结构体中的成员的。
结构体大小
结构体大小?这结构体还有大小的吗,可能有些读者就有疑惑了。其实结构体也是有大小的,其他的数据类型都有大小,结构体当然也有大小,但是不一样的是其他数据类型的大小都是固定的,但结构体的大小却不是固定的,因为你永远不知道结构体里面会有多少个成员变量,你也不可能把结构体变量直接设成最大的容量,这样太浪费空间了,所以设计者就把它设计成了,跟你每次有多少个成员变量有关。
那么结构体大小是否就是等于它里面的成员的大小相加呢?咱们来看代码。
来看一下这三个结果,一个是8,两个是12。
???
不是吧,大哥。第一个和第二个一样的成员,你的大小不一样就算了,我第三个可是比第二个还多一个成员哦,大小居然还是一样的,这是为什么呢。
让我们一个问题一个问题的分析,首先为什么会打印出来8。
这个时候我们就要引入一个新的概念了:
结构体内存对齐
来看图,这里说的很详细了,如果不太想看文字描述的话,我来分析一下。
就拿我们的改过的s1来看
struct S1
{
char c;
int a;
}s1;
首先char类型大小为1,它的对齐数也是为1(这比默认对齐数8要小所以取较小值1),所以c占1个字节,现在到了int a,int类型大小为4,对齐数大小也为4(同样的取4),这个时候不能在第二个位置继续放int了,得找到4的倍数,也就是4,才能开始放int。如图:
最终大小也就是8了。
如果还是不太相信,我们来看S2:
struct S2
{
char c;
int a;
char b;
}s2;
根据我们刚学的知识分析,前两个是一样的,就多了一个char,根据之前的经验char应该是哪个位置都能放的,所以最终大小应该是9的,但是可以看到上面的结果是12,这又是为什么。其实我们结构体最终大小确定的时候也是看对齐数的,看的是成员中的最大对齐数,这里最大对齐数是4,所以最终结构体的大小就是4的倍数,也就是12。
那么S3也就很明确了,多了一个char不影响最终大小,因为没超过12。而且还节省了一点空间。
所以从上述例子中我们可以发现,在结构体中成员的顺序也很重要,所以在你设计结构体的时候可以注意一下顺序,这样可以省下空间。
还有第四条:
可以看到这里的大小是8,我们可以明白当你嵌套了一个结构体,在最终计算结构体的时候,考虑最大对齐数的时候需要把嵌套结构体里的最大对齐数给考虑进去。
最后说一下为什么存在内存对齐这个东西。
大部分的资料是这么说的: