欢迎光临
我们一直在努力

自定义类型:结构体

1.结构体类型和声明

结构体是一些值的集合,这些值成为成员变量。结构的每个成员可以是不同的类型的变量。

结构体的声明,假如我们描述一个学生:

struct S
{
char name[20];
int age;
//成员变量等等;

};

1.1结构体变量的创建和初始化

我们在打印成员的时候,只需要写我们所创建的变量,让后.成员名。

当然,如果我们不想按顺序打印这些成员变量,也可以按我们所指定的去打印。这时只需要我们在初始化的时候稍微修改一下,步骤如下:

只需要把初始化的时候,此时已经创建了变量s,只需要.成员名就可以了。

1.2结构的特殊声明

在声明结构体的时候,可以不完全声明,也就是不创建一个变量,比如:

struct
{
int age;
char name[20];
}x;

此时就把结构体的变量名隐匿了,这样的代码只能使用一次,因为使用一次之后,如果没有对结构体类型进行重命名的话,只能使用一次,所以当使用了一次之后就不能使用了。

这里的x是我们在使用这个结构体时,创建了一个名字,当使用一次之后就没有用了。

1.3结构体的自引用

在结构体中包含一个结构体类型可以吗?

比如我们定义一个链表:

struct s
{
int age;
struct s next;
};

这样写正确吗?显然是不正确的,仔细想一下,如果正确,那么sizeof(struct s)是多少?

因为一个结构体包含一个结构体,会无限的大,这样是不合理的。

那么我们如果想要自引用结构体,该怎么做呢?

struct s
{
int age;
struct s*next;

};

我们可以遐想,我们把一个结构体分成俩部分,一部分放成员变量,另一部分放下一个结构体的地址,这样我们可以一个接一个的把这些结构体连接起来,从而又不会占取空间,又能根据地址找到下一个结构体。

2.结构体的内存对齐

2.1结构体中内存的对齐规则

1.结构体的第一个成员对齐到结构体变量起始位置偏移量为0的地址处。

2.其他成员变量对齐到某个数字(最大对齐处)的整数倍的地址处。

对齐数=编译器默认的数与该成员变量大小的较小值。(在vs中默认的数为8),当然我们在下面的学习中,可以将编译器的默认值进行修改。

3.结构体总大小为最大对齐数(每个成员都有一个最大对齐数,它们当中最大的对齐数)的整数倍。

4.如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数的(含嵌套结构体中成员的对齐数)的整数倍。

下面我们从几个练习当中去感受结构体在内存当中是如何存储的。

我们可以看出来结构体大小为8,下面我们跟着上面的对齐方式来看一下为什么是12.

我们可以先把第一个成员对齐到结构体偏移量为0的位置处。由于第二个是int类型,最大对齐数为4,且要放在对齐数的整数倍的位置处,所以就从偏移量为4的位置开始向下存放4个字节的大小,最后一个是char类型,对齐数为1,任何一个数都是它的整数倍,所以按顺序放在偏移量为8的空间里面就可以,最后结构体的总大小就是所有成员中最大对齐数的整数倍,也就是4的整数倍,  因为我们已经占取了8个位置了,所以整数倍只能是12.所以结构体的总大小为12.

如果结构体中有数组呢?大小又如何计算呢?我们可以再来做一个练习。

这里很容易掉进陷阱,我们要记住内存对齐的规则,这里的对齐数=编译器的默认值和成员变量的大小(成员类型的大小,无论创造的数组多大,只取决于它的类型大小)。所以我们根据这个规则和上面的图解,可以得到这个结构体的大小为16.

2.2为什么存在内存对齐?

1不同的平台和编译器访问任意地址的任意数据,方式是不一样的,某些平台只能在某地址处取出其特定的数据。

2.性能原因:结构体的内存对齐可以提高效率,可以理解为拿空间换取时间。

2.3编译器默认值的修改

#pragma这个预处理指令,可以修改编译器的默认对齐数

此时,我们通过修改编译器对齐数来改变结构体大小,但需要注意的是,当我们修改完对齐数之后,要恢复为默认值。

3.结构体传参

我们能可以看到,用两种方法进行传参,那么两种方式,那个方式比较好呢?肯定是第二种方法,传址的方法,原因:选用传址的方法传递参数时,参数会压栈,会有时间和空间上的开销。而如果传递一个值时,会使结构体的空间变大,压栈的空间开销远远大于传址时的方法,所以选用print2方法更好。

4.结构体的位段

首先说明只有结构体才有位段,

什么是位段呢?位段和结构体声明有啥不一样之处呢?

1.位段的成员类型必须是int ,unsigned int或signed int。

2.位段的成员名后边有一个冒号和一个数字。

struct s
{
//后边的数字代表单位bit
char a:3;
char b:4;
char c:5;
char d:4;

};


int main()
{
printf("%zd", sizeof(struct s));
return 0;
}

上述的代码中s就是一个位段类型。那么位段s的大小是多少呢?

最终答案是3

位段在内存中的存储规则:

1.申请到一块内存中,从右往左使用

2.剩余的空间,不足下一个成员使用时,直接浪费,开辟下一个字节空间。

超详细解读位段内存的存储方式:

看表格,首先a变量占3个bit位,此时这个字节单位里面还剩5个bit位,足以放下下一个变量b(占4个bit位),所以这两个共用一个字节,接着还剩下1个bit位,不足放下c(5bit位),所以直接放弃这一个空间,开辟一个新的1字节单位的空间,此时c放到其中,还有3个bit位,放不下d(4bit位),所以继续开辟一个字节单位的空间。所以位段所占的内存大小为3个字节大小。

赞(0)
未经允许不得转载:171主机测评 » 自定义类型:结构体
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址