自定义类型一:结构体及结构体与位段的“渊源”
作者:互联网
目录
小插曲:宏offsetof显示结构体成员相对于首地址的偏移量。
前言
我们知道,生活中的事物仅仅用C语言规定的数据类型来定义是远远不够的。比如描述一个人,此时我们就需要用到自定义类型中的结构体来描述了。又比如我们需要定义很多常量,如果一味地用define定义,那么看起来会很冗余,而且不方便管理,此时我们就需要用到枚举这个自定义类型。
好的,了解了这些之后,我们进入正文,关于自定义类型的内容。
一,自定义类型之结构体
1.1结构体基础知识
1.1.1结构体的声明
首先是结构体的声明,初始化以及自引用。如下代码所示:
我们声明了一个名为stu的结构体,该结构体有三个成员分别为 长度为10的name数组,整型的成员age,以及长度为10 的sex数组,分别表示该学生的名字,年龄以及性别。这就是结构体的声明,当然,不能省略的是结构体最后的分号。
1.1.2结构体的初始化
结构体可以有以下三种初始化方式,如下所示:
struct stu
{
char name[10];
int age;
char sex[10];
}s1 = { {"张三"},20,"男"};//第一种结构体内初始化
struct stu s2 = { {"李四"},24,"男"};//第二种全局变量初始化
int main()
{
struct stu s3 = { {"王五"},21,"女" };//第三种主函数内初始化
return 0;
}
首先,第一种是在结构体末尾,第二种是设置为全局变量的初始化,第三种为主函数内初始化,三种形式均可。
1.1.3结构体的自引用以及嵌套
结构体是可以自引用的,就相当于自己调用自己;同时,结构体也是可以嵌套的,即在结构体内部添加另一个结构体,用以表示更为复杂的情况。
如上图所示,在结构体Node内部定义了三个成员,分别为整型的data,结构体stu,以及自引用结构体N。这里第二个成员为嵌套的结构体,第三个成员为自引用结构体。那么我们知道,这样的结构体就可以表示生活中比较复杂的事物了。
1.2结构体内存对齐
因为相对来说,结构体内存对齐是一个比较重要的知识点,小编为大家准备了一篇详细的文章供大家参考,如有需要,还请移步:结构体内存对齐_憨憨二号(*•̀ᴗ•́*)و ̑的博客-CSDN博客
但是这里小编还是需要提到关于结构体内存对齐的几个方面:
1.结构体第一个成员在内存中是存放在偏移量为 0 的位置。
2.之后的成员偏移量为:成员本身大小与编译器的默认对齐数取较小值,该值的整数倍数处。
3.整个结构体大小必须为:所有对齐数中的最大值的整数倍数(如果有嵌套,也是一样)。
对于第三条,小编再为大家解释一下:就是当所有的成员按照规则放置成功后,如果该偏移量不在某数(所有成员的最大对齐数)的整数倍数处,就需要增加到该数的整数倍数处,比如本来是到11,但最大对齐数时4,所以整体大小为12。
小插曲:宏offsetof显示结构体成员相对于首地址的偏移量。
为结构体而生的一个宏:offsetof,基本格式为 size_t offsetof( type,member);
首先,第一个参数type为结构体类型名字,第二个参数member为结构体成员名字。该宏计算的是某个成员相对于首地址的偏移量,具体实现如下所示:
#include<stdio.h>
#include<stddef.h>
struct s
{
int a;
char b;
int c;
};
int main()
{
printf("%u\n", offsetof(struct s, a));//0
printf("%u\n", offsetof(struct s, b));//4
printf("%u\n",offsetof (struct s, c));//8
return 0;
二,结构体实现位段
2.1什么是位段
位段,类似于结构体:结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,但是不同的是,位段每个成员后面都有一个冒号和一个数字。
需要注意的几个点:
1.每个成员后面的数字表示该成员在内存中存放的二进制位数。
2.位段的成员都是整型家族的包括整型和字符型。
3.所以位段的开辟总是以4个字节或者1个字节去开辟的。
2.2位段在内存中的存储
这里小编主要为大家分析一下,位段在内存中的存放,大概和结构体内存对齐是差不多的:
重点:当前平台:vs2019
上图所示是一个位段的声明和成员的初始化,可以看到成员a的值为10,但是其在内存中只能存放3个比特位,后面三个成员也是一样分析。那么,如下图所示:
了解具体的存放形式之后,我们将其放入编译器分析如下所示:
当前编译器为:vs2019
如上图所示,在内存中该位段变量 s 的存储形式为:62 46 cc cc ,每个字节(8个比特位)从左到右,其地址为由高到低,这里是先存放低地址位,然后存放高地址位;然后当前编译器为vs2019,字节序列存储形式为小端模式,所以该位段变量 s 的四个char型成员在内存中是按照上图所示存储的。
然后关于这里最后两个字节内容为 cc cc ,虽然这里我们没有用他们,但是他们的内容变成了 c。其实这里只是该位段在初始化时,自动修改的,当该空间内容没有修改时,依旧保持原先更改的值。(这里跟函数栈帧类似哦!)
2.3位段的不移植性
好像这样看来,位段的存储也就那么回事,但是这里可能我们忽略了几个点:
1.这里只是表示了char类型的成员存储,并没有 int 类型的存储,但其实,关于整型的存储时,按照无符号还是有符号数存储没有定义。
2.因为机器的不同,有 16 / 32 / 64 位平台之分,而最小的 16 位平台只能存放 16 位,如果这里打算将一个整型放置 30 位(即在声明时),明显是不满足的。
3.当前面一个成员剩余的位数不足以容纳第二个成员,该剩余位数是舍弃还是利用是未知的。
4.位段中的成员是从左向右分配还是从右往左分配时未知的。
所以,因为这些内容在C语言标准中为定义,故位段的使用,不建议移植平台使用,如果想要在当前平台使用,最重要的还是要知道当前平台的使用方法。
好的,关于自定义类型中的结构体到这里就结束啦,如有问题,还请各位大神指正呀!
标签:初始化,1.1,自定义,成员,位段,体及,对齐,结构 来源: https://blog.csdn.net/qq_52777887/article/details/122794356