这周一时兴起,想写两篇文章来拿个卷吧,今天也是又来写一篇博客了,也是该结束自定义类型的学习与巩固了。
常常会回顾努力的自己,所以要给自己的努力留下足迹。
为今天努力的自己打个卡,留个痕迹吧
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 小闭