本章重点
结构体
结构体类型的声明
结构体的自引用
结构体内存对齐
结构体传参
结构体实现位段(位段的填充&可移植性)
枚举
枚举类型的定义
枚举的优点
枚举的使用
联合
联合类型的定义
联合的特点
联合大小的计算
结构体
结构体的声明
结构的基础知识
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
结构的声明
struct tag
{
member-list;
}variable-list;
创建结构体:
eg1:
一本书(书名,价格,书号)
struct Book
{
char name[20];
int price;
char id[12];
};
eg2:
![](https://img-blog.csdnimg.cn/img_convert/2d4983180549e3a738d63b8dae8eb520.png)
结构体全局变量与局部变量的定义:
![](https://img-blog.csdnimg.cn/img_convert/ca3b3a8e3390b107da05bd19fa833b8e.png)
全局变量定义在main函数之外变量名直接定义在结构体后加';'
局部变量定义在main函数之内:结构体类型加变量名。
匿名结构体类型:(不完全声明)
![](https://img-blog.csdnimg.cn/img_convert/da48a8920e08768213ab34a862f339af.png)
结构体在定义的时候没有标签 (只能使用一次)
两个相同内容的一个为结构体一个位结构体指针之间的关系:
![](https://img-blog.csdnimg.cn/img_convert/9d4e1a860202161179b1e88222a968e6.png)
匿名结构体指针指向匿名结构体(虽然两个结构体里面的内容一样的但是还是不能引用)
警告:编译器会把上面的两个声明当成完全不的两个同类型。所以是非法的。
结构体的自引用:
eg:
![](https://img-blog.csdnimg.cn/img_convert/471357e797b8241d82a134bd1b51def9.png)
//行不通,结构体一直循环访问自己。(死递归)
正确的自引用:
![](https://img-blog.csdnimg.cn/img_convert/923810f9a8203b8db69cff452290048d.png)
位指针变量后结构体大小就方便计算(4|\8)
不是包含同类型结构体变量,而是包换同类型结构体指针。
重命名:
![](https://img-blog.csdnimg.cn/img_convert/4129eb5559fc3f5c5d9fc35234f4fc5f.png)
先命名标签,再引用,再改名。
结构体初始化:
![](https://img-blog.csdnimg.cn/img_convert/cea502740a0a295e78b31d492802f34e.png)
先声明,在main函数中定义,可用'.'或者->来找到要定义的变量。
结构体内存对齐:
规则:
![](https://img-blog.csdnimg.cn/img_convert/56e7649acdfddbf1b08d327ff100832a.png)
eg:
![](https://img-blog.csdnimg.cn/img_convert/6f2552dc21393daa2fc00bc690ea906a.png)
char占一个字节所以成员大小为1,与默认对齐数比较。1<8较小值(VS的默认对齐数为8)
故char c1占一个内存空间,如图中红色区域。\
int占四个字节,所以成员大小为4,与默认对齐数比较。4<8较小值
故存放i时要从储存位置为0的位置计算,对齐到4的倍数当中。如图c1的空间加3为4所以蓝色区域为i所占的空间
double为8个字节前面c1和i正好占了8个空间,所以不需要再浪费多余空间直接可以存放。
故sizeof(s2)=16。
补:VS默认对齐数位8,Linux默认对齐数不确定。
如何计算:
![](https://img-blog.csdnimg.cn/img_convert/c44f4a46c4dca59e3a8b66e9e472b53b.png)
求循环嵌套的结构体大小:
eg:
![](https://img-blog.csdnimg.cn/img_convert/dc65695140825e98a1b419011a8c45d8.png)
![](https://img-blog.csdnimg.cn/img_convert/817c0de83a6a235be4a8ddd806c1918f.png)
前面我们已近叫过普通类型的存放,我们直接讲嵌套结构体的存放:
s4结构体中最大对齐数为8,所以要按8的倍空出空间来存放,因为前一个为char类型说一要浪费7个空间来补8.且s4的内存大小为16所以存放16个空间内存。(红色区域)
因此s5的大小为8+16+8=32.
重点归纳:考虑嵌套结构体内最大对其数,而不是结构体总的内存字节和默认最小对齐数比较
内存对齐规则的原因:
![](https://img-blog.csdnimg.cn/img_convert/460d64f0799731a9cad9c271f18e822d.png)
![](https://img-blog.csdnimg.cn/img_convert/25303d5cdc7bd1c38ef77c6c296f99e4.png)
按存放规则存放和挨个存放比较:
设平台每次读取的内存大小为4
按规则存放的读取c和i只需各读取一次就可以读取完。
按挨个存放i需要读两次才能读全。
总结:拿空间换时间。
如何根据才能放规则存放才能做到空间最少?
![](https://img-blog.csdnimg.cn/img_convert/6c7374817c9567d338d3297b23d17651.png)
让所占空间类型小的存放在前及可作做到空间上的减小。
修改默认对齐数:
![](https://img-blog.csdnimg.cn/img_convert/2af3b520f0a751d7c663422681897498.png)
#pragma pack(num) num为要修改的对齐数
结尾在写一个pragma pack()说明只在这两个pragma区间内默认对齐数被改变,完事后再改回来。
计算结构体中某变量相对于首地址的偏移:
offsetof 头文件<stddef.h>
![](https://img-blog.csdnimg.cn/img_convert/cb06c83afb9713e8849b0a03cfe0a833.png)
参数:要求的结构体,要求的结构体内部元素
![](https://img-blog.csdnimg.cn/img_convert/adc3b47135d4392964f62a765cf5103a.png)
结构体传参:
![](https://img-blog.csdnimg.cn/img_convert/b4c6347deb1dab38d26592150dc357c6.png)
![](https://img-blog.csdnimg.cn/img_convert/a68eed89281cad931f4aa6b7c63bec36.png)
指针传参不会啊考虑有压栈的可能,节省的内存的空间大小。
若想防止形参改变实参可以使用const
位段:
![](https://img-blog.csdnimg.cn/img_convert/c27636f6056a52025af48c5beaf2e37d.png)
位段内部类型位 egint a :num(数据类型,名称‘:’所占的比特的大小)。
![](https://img-blog.csdnimg.cn/img_convert/34ff0ce8bf13188fa4ce1e797865c25f.png)
存放规则:
先使用低比特位的数据再使用高比特为的数据(右向左)
当一块空间剩余空间内容不够下一段使用,则被浪费掉
优点:节省了内存空间
![](https://img-blog.csdnimg.cn/img_convert/b0ff1b76d8328558dc9836394836bd34.png)
缺点:
![](https://img-blog.csdnimg.cn/img_convert/18a59ef1e9e062a670c29bf15198da79.png)
枚举:(与define作用相同)
https://blog.csdn.net/qq_28576837/article/details/125091771
(可参考链接)
![](https://img-blog.csdnimg.cn/img_convert/6785893b6061bd2e17e9fcc1b88cc7e3.png)
联合体:
![](https://img-blog.csdnimg.cn/img_convert/984976df3111f01c4512bf380aff0ab0.png)
关键字:union
元素的地址相同。
![](https://img-blog.csdnimg.cn/img_convert/8e83fee643066a9d4a868d2a4d4035bb.png)
共用同一空间
![](https://img-blog.csdnimg.cn/img_convert/cb5050645ec57193bce05307e4bfc89b.png)
联合体特点:
![](https://img-blog.csdnimg.cn/img_convert/bc5624c1087dbf96e654d933b5f1a8b2.png)
空间按所占空间类型最大的类型来计算。
联合体初始化:
![](https://img-blog.csdnimg.cn/img_convert/ede270a9314fe67aee9ee9c1840ec4f2.png)
每个成员都一样,同一时间只能用一个。
(不方便挨个填写每个成员的大小)
联合体大小的计算:
![](https://img-blog.csdnimg.cn/img_convert/bab7cf4eb93aed6d5d75454cd8050090.png)
按所占空间大的类型来规定最大对齐数。
eg:
![](https://img-blog.csdnimg.cn/img_convert/2532c23826a38f2c2d00c2c29b03442c.png)
![](https://img-blog.csdnimg.cn/img_convert/c8a92dd930d787858676837b4a2a104c.png)