众所周知,自定义类型有三种,一种是结构体,一种是联合体,还有一种是枚举。而我们今天要讲的是第一种结构体。
结构体的定义和初始化
结构体的定义是很简单的,主要是初始化和创建,那么就看具体代码吧。
这个就是结构体从创建到初始化的具体过程,别看着简单,其实非常需要动手操作一遍,才能够不在细节上犯错误。
结构体的特殊声明
这里有一个重要的知识点,就是我们的匿名结构体类型,就是没有tag的结构体,如下图所示,是不合法的。
因为这两个都没有名字,如果在main方法里面使用的话,编译器也不知道该用哪个,所以是不合法的。
结构的自引用
顾名思义,就是结构体自己引用自己,而说起结构体的自引用就会牵扯到链表,这个是相关联的,而链表就是由一个一个节点组成的,而每个节点都分为数据值和下一个节点的地址两部分构成。这就叫链表。而结构体的自引用是这种链表的实现方式。来,设想一下,一个结构体里面既包括这个数据,又包括下一个结构体,结构体里面包含结构体,这显然放不下,而且有点荒唐,不合法。那么,我们包含下一个节点的地址就可以说的过去,因为一个地址的大小是4/8个字节,而结构体比地址大得多,所以放地址是再合适不过了。所以,节点的创建就可以使用结构体的自引用来实现。值得注意的是,上面刚说的匿名结构体类型是1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处 2.其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。 对⻬数=编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。不可以自引用的哦!
结构体的内存对齐
这个是很重要的,这是我们结构体的存储方式,对于我们深入理解结构体来说至关重要。所以什么是内存对齐呢,首先我们要了解内存对齐规则:
1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
2.其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。
对⻬数 = 编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。
VS 中默认的值为 8
Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩
3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的 整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构 体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。
这就是我们的内存对齐规则。这怎么理解呢。
第一条,意思是说从开始保存的位置开始保存;
第二条,我们编译器的默认对齐数和这个数的类型所占字节的大小作比较,从那个数的整数倍的位置开始存储,接下来的每个成员都是这样的规则,知道最后一个成员保存完;
第三条,这个结构体的总大小是刚刚所有类型所占字节大小和默认对齐数比较,找到一个最大的,整个结构体大小就是这个数的整数倍。
第四条,如果嵌套了别的结构体那就从结构体内部比较出一个最大的数,去到他的整数倍位置开始存储,总大小比较时也要比较结构体内部的那些数字。
这就是对齐规则的意思。
修改默认对齐数
修改默认对齐数可以用下面这个:
#pragma pack(1) //设置默认对⻬数为1
#pragma pack() //取消设置的对⻬数,还原为默认
这就是修改和还原的形式。
好的,这就是结构体的部分知识点了。