自定义类型一:结构体及结构体与位段的“渊源”

目录

前言

一,自定义类型之结构体

1.1结构体基础知识

1.1.1结构体的声明

1.1.2结构体的初始化

1.1.3结构体的自引用以及嵌套

1.2结构体内存对齐

小插曲:宏offsetof显示结构体成员相对于首地址的偏移量。

二,结构体实现位段  

2.1什么是位段

2.2位段在内存中的存储 

2.3位段的不移植性 


前言

我们知道,生活中的事物仅仅用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语言标准中为定义,故位段的使用,不建议移植平台使用,如果想要在当前平台使用,最重要的还是要知道当前平台的使用方法。

 好的,关于自定义类型中的结构体到这里就结束啦,如有问题,还请各位大神指正呀!

                                          

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值