1、匿名结构体
什么是匿名结构体?顾名思义,定义结构体类型时没有标注名称,此时这个结构体便为匿名结构体.
由于匿名结构体的特点,创建匿名结构体变量只能在定义匿名结构体时创建。
关于匿名结构体有一个非常有意思的点,用两个不同的匿名结构体创建的变量,即便定义这两个匿名结构体时内容完全相同,编译器也会默认这是两个不同的类型。
所以,这样的赋值是行不通的。
当然,如果你想让匿名结构体能够重复使用,可以使用typedef对匿名结构体进行重命名,但这样实质上就与普通结构体没有区别了。
2、结构体内存对齐
A、什么是结构体内存对齐
我们来看下面这段代码:
正常情况下,我们会自然而然地认为输出结果应为5,但实际上输出结果为8,因为结构体存在内存对齐
在解释结构体内存对齐之前,我们要先了解几个相关概念:
a、内存偏移量
计算机在内存中开辟一块空间,则这块空间最开始的一个字节偏移量为0,之后的一个字节偏移量则为1,以此类推
b、对齐数
在VS编译器下存在一个默认对齐数8
在VS编译器下,变量实质上的对齐数为变量大小和VS编译器默认对齐数这两者中的较小值
PS:其它编译器下,如gcc等,不存在默认对齐数,此时对齐数即为变量的大小
当然,我们可以主动对默认对齐数进行设置:
c、内存对齐
结构体内存对齐有两条规则:
1、除去偏移量为0的位置处(任何变量的内存空间都可由此开始,具体是什么变量由此开始,取决于结构体中的成员顺序)
结构体中各成员的内存空间要从内存偏移量为其对齐数的整数倍位置处开始。拿上面这段代码进行说明:
a创建之后,占据了偏移量为0的内存空间,紧接着的是偏移量为1的内存空间,而对于b而言,对齐数为4,所以此时,b所占内存空间应从偏移量为4处开始,占4个字节。
2、结构体变量所占内存大小应为该结构体各个成员对齐数中最大对齐数的整数倍
如上面这段代码,b所占内存空间应从偏移量为4处开始,占4个字节,因而实质上,a对应有4个字节的空间(占一个字节,废弃三个字节),所以整体上该结构体占到8个字节,而该结构体的最大对齐数为4,8是4的整数倍,符合规则,故结构体大小就为8个字节。
此处,如果我们将代码做如下修改:
此时输出的结果仍为8,但实质上,8的得到,二者是有所不同的
对于这种修改之后的情况,b从偏移量为0的位置处开始向后占4个字节,由于a的对齐数为1,所以内存空间在紧随着的偏移量为4的地方即可开始,占一个字节。
但注意,此时整个结构体的大小不过5个字节,不满足最大对齐数(4)的整数倍,因而还要再扩充3个字节(当然,这3个字节没有储存任何东西,是浪费的),因而我们最后得到的大小即为8个字节
B、为什么要有结构体内存对齐
结构体内存对齐,不可避免地会造成一些内存的浪费,既然如此,为什么还要设计结构体内存对齐呢?
这可以从两个方面来进行解释:
a、平台原因
不是所有的硬件平台都能够访问任意地址处的任意类型的数据的。有些平台只能访问某些特定地址处的特定类型的数据,否则就抛出硬件异常。
b、性能原因
数据结构应尽量在自然边界上对齐,这样处理器在访问对齐的内存时,往往只需要一次访问即可;而对于未对齐的内存,处理器往往要进行两次访问,这样访问的效率就下降了。
所以,从这个角度上来讲,结构体内存对齐实质上是拿空间去换取时间。