在对结构体有了较为明晰的认识后,我们当然要进行下一步更深层的认识
目录
1.匿名结构体
我们知道,数组有不完全初始化,未初始化的数值默认为0,而结构体则有其不完全声明的特殊情况存在——称之为匿名结构体类型
struct
{
char name[20];
float height;
int age;
}s1,s2;
这类结构体的特点有两个:
①匿名结构体会省略结构体标签(只有struct来定义结构体类型)。
②变量只能定义在大括号后面而不能重新定义结构体的局部变量。
2.结构体的自引用
结构体成员可以包含其他的结构体,那包含一个为该结构本身的成员是否可以呢?
2.1错误的自引用方式:
struct Node
{
int n;
struct Node n;//该结构体自身作为成员
};
我们在vs上进行编译发现它也会报错
因为这种声明是一个循环往复的套娃过程,成员n是一个结构体,n的内部还会有成员是结构体,在给该结构体分布内存时候,由于一直循环,该Node结构体大小是无法确定的,所以这种声明是非法的。
2.2正确的自引用方式
struct Node
{
int a;
struct Node *n;//以指针作为成员变量
};
我们以指针来作为该成员变量自引用,由于指针的长度是确定的,所以编译器在编译过程可以确定该结构体成员的大小,内存分配合理,及成功。当然为了简洁我们也可以将struct Node重新定义一下,也是没有什么问题的。
typedef struct Node
{
int a;
struct Node* n;
}Node;
int main()
{
Node n;
return 0;
}
3.结构体的内存对齐规则
我们在自引用中提到了结构体内存大小这个东西,那么问题来了,对于int来说大小为4字节,char来说为1字节,我们是很明确的,那么结构体的大小应该怎么计算呢?这就要说到我们的结构体内存对齐规则。
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
(VS中默认对齐数为8)
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
这便是结构体内存对齐的规则,我将用实例来清楚解释该规则的适用情况,在此之前我们先来介绍一个宏——offsetof,这个宏是用来计算结构体成员相较于起始位置的偏移量
这个宏需要引用头文件stddef.h,包含两个参数可以返回结构成员变量的偏移量,第一个参数放置结构体类型,第二个放置所求偏移量的结构体成员,如下操作:
我们可以看到对于srtuct s1结构体来说,我们的三个成员的偏移量分别是0、4、8。我们用一个空格作为一个字节来存储数据,具体情况如下:
①:s1的第一个成员char c1我们放在偏移量为0的地址处
②第二个int类型的变量放到“对齐数”整数倍的偏移量处(在vs编译环境,系统默认是对齐数8,而int的对齐数就是其类型大小4,我们选取较小的——4为对齐数)而4倍数的偏移量就有4,所以从偏移量为4的位置开始放置变量i。
③接下来放置c2变量,由于它的对齐数是其变量大小——1<8,所以只需紧挨变量i放置即可,放在我们偏移量为8的位置。
④接下来成员放置完成后计算结构体内存大小,而要求是最大对齐数的整数倍——也就是4的整数倍,我们算下来的是9,所以要变为4的整数倍也就是12,延续到偏移量为11的位置处——这便是按照内存对齐规则计算出来的s1的结构体大小。
(但此时对于s1来说,偏移量为1,2,3位置的空间被浪费了)
s2的大小计算我们如下图所示:
(同样对于s2来说,我们偏移量为2,3的空间也被浪费掉了)
当我们结构体内嵌套一个结构体的时候,大小又是多少呢,我们如下举例:
struct s3
{
double a;
struct s1;
char ch;
};
我们将struct s2放入新定义的struct s3中时,s3的内存大小是多少呢,分析如下:
我们在vs环境下编译也可得到s3的大小确实是24个字节
当然我们也可以将编译器的对齐数修改,只需使用预处理指令#pragma来改变系统的默认对齐数
例子如下:
#pragma pack(1)//修改默认对齐数为1
struct s1
{
char c1;
int i;
char c2;
};
#pragma pack()//恢复默认对齐数
#include<stdio.h>
int main()
{
printf("%d\n", sizeof(struct s1));
return 0;
}
我们依照上例可以算出它的大小变为了6个字节,当我们结构体对齐方式不合适的时候,我们就可以修改其默认对齐数。这便是小编对于结构体的认识啦~,写的不好也希望大家多多意见咯。希望大家多多支持。