自定义类型【2】(位段、枚举、联合)

引言

前面我们了解了结构体的知识。了解了结构体类型的声明、结构体变量的定义与初始化、结构体传参与结构体内存对齐。
除了结构体外,还有位段、枚举、联合这样的自定义类型。

位段

信息的存储一般以字节为单位,但是一些时候我们的数据不需要一个字节的空间。例如int a = 10;,10的二进制补码为01010,实际上只占用了不到一个字节,开辟一个整型的空间就显得有些浪费了。
借助结构体实现的位段就可以解决这个问题:

位段定义

位段(bit-field)是以位为单位来定义结构体中的成员变量所占的空间。

位段中的成员只能是int、unsigned int、signed int、char类型。
位段的成员名后有一个":"后跟一个数字,表示该结构体成员需要开辟几个比特位的空间。

例如:

struct A
{
	int i : 2;
	int j : 1;
	int k : 20;
};

这里的struct A就是一个位段类型。它给i开辟2个比特位;给j开辟1个比特位;给k开辟20个比特位。

我们可以看一下struct A类型的大小:

struct A
{
	int i : 2;
	int j : 1;
	int k : 20;
};

int main()
{
	printf("%d\n", sizeof(struct A));
	return 0;
}

在这里插入图片描述
为什么是4个字节呢?
我们需要了解位段类型是如何开辟空间的:

位段的内存分配

位段在分配内存时,每次开辟一定的空间给位段的成员,成员依次占用这些空间。当本次开辟的空间剩余不足时,才会再开辟一定的空间。直到存放位段中的所有成员。
这个一定的空间对于int类型是4个字节;对于char类型是1个字节。所以在成员后的表示比特位的数字若是int不能超过32;若是char不能超过8。

对于上例的位段类型struct A,里面的类型都是int型的,所以先开辟4个字节的空间。变量i需要2个比特位;变量j需要1个比特位;变量k需要20个比特位。一共只需要23个比特位,4个字节完全够用,所以不需要再次开辟:

在这里插入图片描述

虽然也存在一些浪费,不过相对来说已经节省很多了。

再比如这段代码:

struct B
{
	int i : 2;
	int j : 1;
	int k : 20;
	int x : 30;
};

int main()
{
	printf("%d\n", sizeof(struct B));
	return 0;
}

在这里插入图片描述
到成员k时,已经占用了23个比特位,本次的4个字节只剩9个比特位。显然不足以开辟30个比特位给成员x,需要再次开辟4字节的空间。

那么这剩余的9个比特位是浪费掉还是接着使用呢?

位段的可移植性问题

其实,不只上面的这个关于每次开辟剩余的空间的问题。还有一些问题是C语言标准没有定义的:

1、int是作为有符号数还是无符号数是没有定义的;
2、位段中最大位的数目是不确定的;
3、位段中的成员从低位到高位分配空间还是从高位到低位分配是不确定的。

所以位段与结构体的效果类似,可以很好的节省空间。但是有跨平台问题的存在。

枚举

在初识C语言部分,我们已经初步了解了枚举常量。

枚举就是一一列举,可以用来列举几个常量。例如星期、月份、性别等。这些常量的类型是枚举类型的。接下来就详细介绍一下枚举类型:

枚举类型的定义

enum Day
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sta,
	Sun
};

enum是枚举关键字。Mon、Tues、Wed、Thur、Fri、Sta、Sun这些都是枚举常量,它们之间用","隔开。如果没有赋值,这些枚举常量的值是从0递增1;如果有赋值,赋值的那个成员开始所赋的值递增1:

enum Day
{
	Mon,
	Tues,
	Wed,
	Thur=10,
	Fri,
	Sta,
	Sun
};
int main()
{
	printf("%d\n", Mon);
	printf("%d\n", Tues);
	printf("%d\n", Wed);
	printf("%d\n", Thur);
	printf("%d\n", Fri);
	printf("%d\n", Sta);
	printf("%d\n", Sun);
	return 0;
}

在这里插入图片描述
这些常量的类型都是enum Day。

枚举常量的使用

当我们需要将某个枚举常量的值用作某一个变量的初值是,这个变量的类型需要与枚举类型一致。即只能用枚举常量给枚举变量赋值:

enum Day
{
	Mon,
	Tues,
	Wed,
	Thur=10,
	Fri,
	Sta,
	Sun
};
int main()
{
	enum Day s = Mon;
	printf("%d\n", s);
	return 0;
}

在这里插入图片描述

枚举常量的优点

枚举常量在使用时有许多的优势:

1、枚举常量一次可以定义多个常量,而#define只能定义一种;
2、枚举常量是具有类型的,会更加严谨;
3、使用枚举常量可以提高代码的可读性与可维护性(在后面的通讯录中会做具体的说明);
4、将常量封装,防止了命名污染。

在后面的代码中,大家可以多尝试使用枚举常量,就会发现它的许多便利。

联合(共用体)

联合的定义

联合也是一种自定义类型。在联合中同样包括一系列成员。
联合关键字是union:

union A
{
	char c;
	int i;
};

但是这些成员共用一块空间,所以联合也称为共用体。
由于成员共用一块空间,所以联合的大小至少是最大成员的大小。

我们可以用sizeof来计算这个联合的大小:

union A
{
	char c;
	int i;
};
int main()
{
	printf("%d\n", sizeof(union A));
	return 0;
}

在这里插入图片描述
int型的成员i与char型的成员c共用4个字节。

但除此之外,关于联合大小的计算还有一些规定:

联合的大小

首先,联合的大小至少是其中最大成员的大小;
第二,最终的大小必须是联合中成员最大对齐数的整数倍(对齐数是成员大小与默认对齐数的较小值)。

在上面的例子中,最大成员是int型的,4个字节。成员最大对齐数也是4,所以这个联合union A的大小就是4字节。

再比如:

union B
{
	char c;
	int i;
	short s[3];
};
int main()
{
	printf("%d\n", sizeof(union B));
	return 0;
}

在这里插入图片描述
这个union B联合中的最大成员的大小是6字节,但由于成员最大对齐数是4。联合的大小必须是成员最大对齐数的整数倍,所以就是8。

总结

在本文中,我们了解了位段、枚举、联合的相关知识。

这是虎年的最后一篇博客了,祝大家新年快乐!!!

最后,如果对本文有任何问题,欢迎在评论区进行讨论哦

希望与大家共同进步哦

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
C语言中,结构体是一种自定义数据类型,可以将不同类型的变量组合在一起,形成一个新的数据类型。结构体定义的基本形式如下: ```c struct 结构体名 { 数据类型 成员名1; 数据类型 成员名2; // ... }; ``` 其中,结构体名是用户自定义的名称,成员名是结构体中每个成员的名称,数据类型可以是任意C语言的数据类型,包括基本数据类型自定义数据类型。 结构体变量的定义方式如下: ```c struct 结构体名 变量名; ``` 读取结构体中的成员变量可以通过“.”运算符来实现,例如: ```c #include <stdio.h> struct Person { char name[20]; int age; }; int main() { struct Person p; printf("请输入姓名:"); scanf("%s", p.name); printf("请输入年龄:"); scanf("%d", &p.age); printf("姓名:%s,年龄:%d\n", p.name, p.age); return 0; } ``` 枚举是一种特殊的数据类型,用于定义一组常量。枚举的定义方式如下: ```c enum 枚举名 { 常量名1, 常量名2, // ... }; ``` 其中,枚举名是用户自定义的名称,常量名是枚举中每个常量的名称。枚举常量的值默认是从0开始自动递增的,也可以手动指定值。例如: ```c #include <stdio.h> enum Weekday { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }; int main() { enum Weekday today = Tuesday; printf("今天是星期%d\n", today + 1); return 0; } ``` 联合是一种特殊的数据类型,它的成员变量共享同一块内存空间。联合的定义方式如下: ```c union 联合名 { 数据类型 成员名1; 数据类型 成员名2; // ... }; ``` 其中,联合名是用户自定义的名称,成员名是联合中每个成员的名称,数据类型可以是任意C语言的数据类型,但所有成员的大小不能超过联合的大小。例如: ```c #include <stdio.h> union Number { int i; float f; }; int main() { union Number n; n.i = 123; printf("int: %d, float: %.2f\n", n.i, n.f); n.f = 3.14; printf("int: %d, float: %.2f\n", n.i, n.f); return 0; } ``` 以上就是C语言自定义数据类型中的结构体、枚举联合的基本用法和注意事项。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿qiu不熬夜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值