自定义数据类型

自定义数据类型

结构体

结构体的声明

结构体的基础知识

自定义数据类型

结构的声明

自定义数据类型

变量的声明

自定义数据类型

匿名结构类型

自定义数据类型

结构体的自引用

自定义数据类型

自定义数据类型

结构体变量的定义和初始化

自定义数据类型

自定义数据类型

结构体内存对齐

自定义数据类型

自定义数据类型

第一,第一个成员在偏移量为0的地方,我们假设第一个成员的内存在第二行开始

第二,其他成员要对齐到对齐数的整数倍,对齐数的概念如上图,因为int a的字节是4,vs默认对齐数是8,所以在这里对齐数是4,4的整数倍是4,所以int a在第五行开始,也就是紫色的地方

第三,同第二理char c2的对齐数是1,那么它就在9行,此时这个结构体一共占了9个字节

最后,结构体的总大小是最大对齐数的整数倍,在这里也就是4的最大整数倍,因为此时已经占了9个了,所以是12,所以这个结构体大小是12

很明显,上面的规则中第四个没有使用到,那么结构体嵌套的问题是什么样呢

自定义数据类型

首先计算出结构体s3的大小是16

结构体s4中嵌套了s3

第一,结构体s4中第一个成员是char类型,占一个字节,如右上蓝色

第二,嵌套的结构体对齐到自己的最大对齐数的整数倍,s3中最大对齐数是8,整数倍是8,所以从第八个位置开始,s3的大小已经计算出是16,占16个字节大小

第三,double型的占8个字节,所以向下占8个位置,如右上紫色

最后,可以看出一共占了32个字节(中间红色的是被浪费的)

但结构体的整体大小是最大对齐数(含嵌套结构体)的整数倍,结构体s4中的最大对齐数是结构体s3,也就是16,32是16的整数倍,所以结构体s4的大小是32

有的人可能会好奇,VS默认对齐数是8,那么其他编译器呢。这里如果其他编译器没有默认对齐数,那么该成员大小的最小值就是对齐数

自定义数据类型

那么内存对齐会浪费空间为什么要内存对齐呢

自定义数据类型

那在设计结构体的时候,既要满足对齐,又要节省空间,应如何做

自定义数据类型

修改默认对齐数

#pragma pack(n)

这里的n就是我们自己修改的默认对齐数

自定义数据类型

结构体成员偏移量

offsetof是个宏,不是函数

offsetof–>头文件#include<stddef.h>

自定义数据类型

结构体传参

自定义数据类型

很显然say2传参方式更好,原因:

自定义数据类型

位段

什么是位段

自定义数据类型

位段的内存开辟

自定义数据类型

自定义数据类型

一次开辟一个整形空间,这个整形空间4个字节,32个bite位,a需要2个,b需要5个,c需要10个,这一个空间一共32个,但是已经使用了17个,剩下15个,不够d使用了,那么前面15个bite位全都丢掉,重新开辟一个整形空间,也就是4个字节,32个bite位,然后使用30个bite位给d,剩下两个丢掉,也就是说,这个位段一共使用了8个字节

位段就是为了节省空间存在的

自定义数据类型

结构体的话要开辟四个字节空间,但是位段只需要三个字节空间

位段的弊端

位段不能跨平台,可移植程序应避免使用位段

自定义数据类型

枚举

枚举的基本概念及使用

枚举也就是一一列举

自定义数据类型

自定义数据类型

枚举的优点

自定义数据类型

联合-联合体(共用体)

联合类型的定义

自定义数据类型

联合的特点

自定义数据类型

自定义数据类型

自定义数据类型

判断计算机的大小端存储方式

自定义数据类型

所以如果想要判断存储方式(比如int a的存储方式)是小端还是大端,就可以看第一个字节(一个整型里有4个字节)是不是1

自定义数据类型

但这种方法不太好,我们可以自己封装一个函数

自定义数据类型

也可以利用我们刚学到的联合体的知识解决

自定义数据类型

自定义数据类型

联合大小的计算

自定义数据类型

自定义数据类型


作者:吕文康
学校:山东第一医科大学
2020年11月14日