C语言:结构体及拓展(详)

在C语言中已经提供了内置类型,如char.short.int.long.float.double等等,但是仅仅有这些还不够,比如我想描述一本书,描述一个房间,单凭这些内置是不够的,对此我们引入了结构体这类自定义数据类型

C语言:结构体及拓展(详)_第1张图片

结构是一些值的集合,这些值称为成员变量。结构中的每个成员可以是不同类型的变量,如:数组,联合体,整型,也可以是其他的结构体.

结构的声明

C语言:结构体及拓展(详)_第2张图片

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

创建

C语言:结构体及拓展(详)_第3张图片

初始化

C语言:结构体及拓展(详)_第4张图片

内存对齐(计算结构体大小)

我们可以使用sizeof来求取结构体所占大小,但我们发现对于结构体中不同类型,所占的大小也不同

C语言:结构体及拓展(详)_第5张图片

导致于此的原因是存在内存对齐规则):

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

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

(对齐数=编译器默认的一个对齐数与该成员变量大小的较小值

vs中默认值为8

Linux中gcc没有默认对齐数,对齐数就是成员自身大小)

3.结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)的整数倍;

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

基于此规则,我们可以对上述作出解释

C语言:结构体及拓展(详)_第6张图片

我们也可以通过#pragma这个预处理命令来修改这个编译器默认的对齐数

C语言:结构体及拓展(详)_第7张图片

结构体传参(地址)

当我们得到的是一个指向结构体的指针时,我们可以使用 结构体指针->成员名来是实现间接访问

C语言:结构体及拓展(详)_第8张图片

对于函数传参,参数是需要压栈,会有时间和空间上的系统开销

所以在选择时候 往往是进行地址传参,我们可以在参数前加一个const 保证值不变

进行地址传参,避免了在结构体过大时系统开销过大而导致性能下降的后果

拓展(结构体实现位段)

什么是位段?

位段是通过结构体来实现的一种以位(bit位)为单位的数据存储结构,它可以把数据以位的形式紧凑的储存,并允许程序员对此结构的位进行操作

位段与结构的不同

1.位段的成员必须是int.unsigned int.或signed int,在C99中位段成员类型也可以选择其他类型

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

C语言:结构体及拓展(详)_第9张图片

我们通过printf()函数可以看到该内存为4 但这跟我们上面所说的内存对齐存在冲突这源于空间开辟不同,这大大节省了空间

位段的内存分配

1.位段的成员可以是int,unsigned int,signed int或者是char等类型

2.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的

3.位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段.

对于上述可能有人会有疑问为什么是4(byte),不应该是1(bit)+2+5=1(byte)吗,这里的节省是相对于4个int(16byte)而言,而4byte已经是大大节省了空间

位段的跨平台 问题

1.int位段被当成有符号还是无符号是不确定的

2.位段中最大位的数目不能确定.(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题)

3.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义

4.当一个结构包含两个位段,第二个位段成员较大时,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的

总结

与结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是存在着跨平台问题

你可能感兴趣的:(C语言初阶,c语言,vscode,笔记,经验分享)