【自定义类型:结构体,枚举,联合】(二)

简介: 【自定义类型:结构体,枚举,联合】(二)

2. 位段(位段的填充&可移植性)


2.1 什么是位段:

1 .位段的成员必须是整形家族的成员(int,unsigned int,signed int ,char,unsigned char)

2 .位段的成员名后面有一个冒泡和一个数字。

3 .位段是可以节省空间的

为什么位段可以节省空间呢?


解释:

位段的位代表比特位,我们知道一个字节有8个比特位,当我们定义:

int flag = 1;实际上1只占用了一个比特位,但是int有四个字节,32个比特位,这就难免造成了空间上的浪费,因此利用位段可以节省这个不必要的开销。

比如:

struct A
{
  //4byte-32bit
  int _a : 2;
  int _b : 5;
  int _c : 10;
  //15
  //4byte-32bit
  int _d : 30;
};
//
//47 bit
//6byte - 48bit
//8byte - 64bit
//
int main()
{
  printf("%d\n", sizeof(struct A));
  return 0;
}
  • 那么如何求出A位段的大小呢?


2.2 位段求结构体大小的计算方法:


以上述代码为例,首先我们通过上面的学习认识到,结构体的大小是4*4=16的可能性最先被排除掉,由于引进后面的数字,使其变成相应比特位的大小,如果只是单纯的比特位相加,总和47个比特位,看成48个比特位,就是6个字节大小,但是,这么单纯的相加,也是不对的。计算方法如下:


先看类型,int ,4个字节,32个比特位,因此,由于是int类型,我们先给其4个字节大小,a,b,c一共用了2+5+10 = 17个比特位,而d占30个比特位,加上之后远远大于32个比特位,故我们在给其int大小,即四个字节,这样,由于d在之前的空间放不下,所以d不占用第一个int所给的空间,而是全部占用到第二个4字节中。故struct A的大小为八个字节。


微信图片_20230221155727.png

2.3 位段的内存分配


1 位段的成员可以是int ,unsigned int ,signed int ,char(属于整形家族)类型

2 位段的空间上是按照需求以四个字节(int)或者一个字节(char)的方式来开辟的。

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

4 冒号后面比特位不能超过类型的大小。(char d : 14 是错误的)


微信图片_20230221155844.png

当我们将其转化成二进制的时候,由于位段,需要舍弃其中的一部分比特位,当然,我们并不知道赋值放到内存中是从左到右还是从右到左,故我们假设是从右到左,二进制变成16进制,数字变成:62 03 04 。如上图,那么开始调试转成内存:(在VS编译器)

微信图片_20230221155853.png

>故,我们的假设是正确的。


2.4 位段的跨平台问题


1 . int位段被当成有符号数还是无符号数是不确定的。

2 . 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大12,写成27,在16位机器会出现问题.)

3 .位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

4 . 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

总结 : 跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在.


3. 枚举


3.1 枚举的使用:


enum Day//星期
{
  Mon,//0
  Tues,//1
  Wed,//2
  Thur,//3
  Fri,//4
  Sat,//5
  Sun//6
};
enum Day//星期
{
  //枚举常量
  Mon=1,
  Tues,
  Wed,
  Thur,
  Fri,
  Sat,
  Sun
};

3.2 枚举的优点:


  1. 增强代码的可读性和可维护性。
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
  3. 防止命名污染(封装)。
  4. 使用方便,一次可以定义多个常量。


4. 联合(共用体)



4.1 联合类型的定义


联合也是一种特殊的自定义类型。

这种类型定义的变量也包含一系列的成员,特征是这些成员共用同一块空间(所以联合也叫共用体)。


微信图片_20230221160320.png


4.2 联合的特点


联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少有能力保存最大的那个成员)。


由于联合体的特性,共用一块空间,这就导致他们的首地址是相同的,当我们赋值时,也会由于覆盖的原因,后面赋值在公共的空间会将前面赋值的空间所覆盖,从而导致数的变化。


微信图片_20230221160426.png

我们看到,u.c在u.a的后面赋值,则其会将对应公共的部分进行修改,刀子u.a变成了0x11223300,u.c = 0x00000000;当我们调换一下前后的位置时,发现:

微信图片_20230221160509.png

u.a的公共部分将u.c的部分进行了修改,由此可见,联合体的公共部分是可以由后者改变前者的。


4.3 联合大小的计算


  • 联合的大小至少是最大成员的大小。
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。


首先,对于数组的处理,不能将他看成是void [n]进行计算,对于Un1来讲,char c[5]应该看成char c1,c2,c3,c4,c5;因此占用5个字节,而int占用四个字节。


微信图片_20230221160627.png


现在是五个字节,要变成最大类型的整数倍,因此sizeof(union Un1)的大小为8,;同理,Un2的大小为16.

微信图片_20230221160637.png


5. 总结:


通过以上的对自定义类型的详解,可以让我们根据实际情况和具体的需求来节省空间和时间上的消耗,从而获得最大的效益。好了,本篇文章的分享到此结束了,码字不易,你们的支持将是我坚持的不竭动力。


相关文章
|
4月前
|
Linux C语言 C++
自定义类型——结构体、枚举和联合
自定义类型——结构体、枚举和联合
|
2月前
|
编译器
自定义类型:联合和枚举
自定义类型:联合和枚举
27 0
|
7月前
|
存储 编译器 Linux
自定义数据类型:结构体+枚举+联合
自定义数据类型:结构体+枚举+联合
|
存储 编译器 C语言
自定义数据类型:结构体,枚举,联合
自定义数据类型:结构体,枚举,联合
|
存储 编译器 Linux
自定义类型——结构体,枚举,联合
自定义类型——结构体,枚举,联合
|
编译器 C++
【学习笔记之我要C】自定义类型详解(结构体+枚举+联合)
【学习笔记之我要C】自定义类型详解(结构体+枚举+联合)
298 0
|
编译器 C++
自定义类型:结构体,枚举,联合 (1)
自定义类型:结构体,枚举,联合 (1)
73 1
|
编译器 C++
自定义类型:结构体,枚举,联合
自定义类型:结构体,枚举,联合
|
存储 编译器 C++
自定义类型:结构体,枚举,联合 (2)
自定义类型:结构体,枚举,联合 (2)
67 0
|
存储 安全 编译器
自定义类型:结构体,枚举,联合
自定义类型:结构体,枚举,联合
115 0