自定义类型(二)结构体位段,联合体,枚举

本文介绍了C++中结构体的默认对齐数修改,位段的声明和使用,联合体的概念及其实际应用,以及枚举类型的用途。通过实例展示了如何优化内存使用和提高代码可读性。
摘要由CSDN通过智能技术生成

这周一时兴起,想写两篇文章来拿个卷吧,今天也是又来写一篇博客了,也是该结束自定义类型的学习与巩固了。

常常会回顾努力的自己,所以要给自己的努力留下足迹。

为今天努力的自己打个卡,留个痕迹吧

                                                                                                       2024.03.30     小闭


目录

结构体默认对齐数的修改

结构体的实现位段

联合体

联合体的实际使用

枚举类型


结构体默认对齐数的修改

在别的编译器可能没有,但在VS中我们是可以自己修改默认对齐数的,毕竟有的编译器都没有默认对齐数,而在VS中不仅有默认对齐数还可以修改默认对齐数。那我们该如何修改结构体的默认对齐数呢,首先我们就需要认识一下这个预处理命令  #pragma。

下面就举一个代码示例吧

注:如果还没了解结构体大小如何计算的小伙伴,可以看一下这篇文章。http://t.csdnimg.cn/j7uiv

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

#pragma pack(1)    //设置默认对⻬数为1
struct S
{
	char c1;
	int i;
	char c2;
};
#pragma pack()      //取消设置的对⻬数,还原为默认
int main()
{
        
	printf("%d\n", sizeof(struct S));
	return 0;
}

现在这段代码默认对齐数已经为1了。

那我们现在就可以按照之前的步骤,来继续计算结构体的大小了。

首先因为默认对齐数为1,那么几乎所有成员的对齐数都是1了,那么这么排列下去也是没有空余的地方浪费。如图:

如图显而易见按照之前的说法,结构体大小为成员最大对齐数的整数倍那么这里把默认对齐数改为1后,导致所有的对齐数为1,而任何数都是1的倍数,所有这里结构体大小就为6.

这么一看当修改默认对齐数为1时,结构体大小其实就是所有成员大小的总和。


结构体的实现位段

 位段的声明和结构是类似的,有两个不同:

1. 位段的成员名后边有⼀个冒号和⼀个数字。

2.位段的实现要在结构体来实现

例如:

struct A
{
 int _a:2;
 int _b:5;
 int _c:10;
 int _d:30;
};

 那这代表什么呢?

那代表这位成员变量只占后面数字的bit位,如_a就只占2个bit位

1. 位段的成员可以是 int unsigned int signed int 或者是 char 等类型

2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的⽅式来开辟的。

3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

那位段是怎么存储在内存中呢?

我们再来看一段例子:

struct S
{
 char a:3;
 char b:4;
 char c:5;
 char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

 上面说到位段通常是按一个字节或4个字节开辟的,在上面的例子中是以一个字节来开辟的,

那这开辟一个字节的空间是从左到右储存还是从右到左,其实这在C语言中是没有定义的,但在VS里是从右到左的。

注意在开辟空间时:

当一个字节不足以存储下一位成员时,就会在开辟下一个字节,这里一共开辟了三个字节,所以这里结构体的大小就为3个字节

那我们在来看一下内存中存储形式是否如我所写

显然和我所写是一样的。 那位段就讲完了。


联合体

联合体与结构体一样都是自定义类型,他的成员可以是任何类型,但它与结构体不同的是,他只为成员内占用空间最大的成员开辟空间,其它成员和它共用一块空间,所以我们也叫它共用体

从上面的描述来看可能初学联合体的小伙伴可能就疑惑了,只为空间最大得成员开辟空间,那空间肯定不够给成员,那不出问题了,一开始我也这么想,但后来我才明白,联合体不像结构体,他的使用只能使用一次,在它的成员里,你只能在一次使用中选出一位成员进行赋值使用,不然就会出现错误。


联合体的大小

联合体大小上面说了其最少也要有最大成员的大小,因为其使用一次只存储一个成员,只要储存得下最大的成员那也可以把其它成员存储得下。

联合体的特点

联合体的特点就是所有成员共用一块空间。

下面用一段代码给大家看看其特点

union Un
{
	char a;
	int b;

};


int main()
{
	int a = 0x11223344;
	

	union Un un = { 0 };
	un.b = 0x11223344;
	un.a = 0x55;
	printf("%x\n", un.b);


	return 0;
}

这里我们先是给nu.b赋值0x11223344,然后再给un.a赋值0x55,然后观察其在内存中的变化,很容易发现其在un.b上的内存上改变了内存的存储,很显然其确实是一块空间共用,这样在一定程度上减少了内存的使用。 

 


联合体的实际使用

我们用一个实际情况来举例

现在要推出,⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯子、衬衫。 每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。 图书书名、作者、页数  ,杯子设计, 衬衫:设计、可选颜色、可选尺寸

那我们就可以很容易的写出一段联合体代码解决这个问题

struct giftList
{
 int stock_number;//库存量
 double price; //定价
 int item_type;//商品类型
 
 union{
 struct
 {
 char title[20];//书名
 char author[20];//作者
 int num_pages;//⻚数
 }book;
 struct
 {
 char design[30];//设计
 }mug;
 struct
 {
 char design[30];//设计
 int colors;//颜⾊
 int sizes;//尺⼨
 }shirt;
 }item;
};

枚举类型

 枚举类型如其名,就是将东西一一列举,列举后他们就可以代表一段数字,方便我们使用。

例如:

enum en
{


	book,
	milk,
	egg,
	football

  

};

这里从上往下book代表数字0,milk代表数字1,这样往下他们这样就可以代表一个数字,这样的好处是,当我们让用户选择一个物品时,我们把枚举的成员写进代码中,当用户选择时,我们的程序就可以用一个简单的数字传回,来代表这个物品,且用户也一眼方便看出自己选择的是什么,而不是选择一个数字,然后按照数字看菜单这个数字代表什么。 

编译器也是直接显示出来给我们看,这里book就代表数字0. 


 文章已到末尾

常常会回顾努力的自己,所以要给自己的努力留下足迹。

为今天努力的自己打个卡,留个痕迹吧

                                                                                                       2024.03.30     小闭

  • 61
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 48
    评论
评论 48
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值