0


【C语言】自定义类型—位段、枚举、联合体

1.位段

什么是位段

位段的声明和结构体是类似的,但有两个不同的地方。

  1. 位段的成员必须是int,unsinged int 和signed int 或者是char(属于整型家族)类型
  2. 位段的成员名后有一个冒号和一个数字 例如:
structA{int a :2;int b :5;int c :10;int d :30;};//struct A就是一个位段类型

那位段A的大小是多少?

printf("%d\n",sizeof(structA));

位段类型struct A的大小
为什么是8呢?
在位段中:

位:二进制位

structA{int a :2;//占2个bite位int b :5;//占5个bite位int c :10;//占10个bite位int d :30;//占30个bite位};
  • 4个成员变量都是int类型的,最开始只开辟4个字节的空间,然后在它们分别占用的比特位空间处放入数据
  • 最开始开辟4个字节,共32个bite位,a占2个,b占5个,c占10个,此时一共使用了17个bite位,还剩15个,d占30个,剩余不够d使用,在重新开辟4个字节将d放入其中,共使用8个字节。
  • 放入方式是固定的一种形式,下面便是我们对这种方式的学习。

位段的内存分配

  1. 位段的成员可以是int、unsigned int、signed int 或 char类型
  2. 位段的空间上是按照需要以4个字节(int)或1个字节(char)的方式来开辟的
  3. 位段涉及很多不确定因素,位段是不跨平台的,注意可以执行的程序应该避免使用位段。
  • 位段中int类型和char类型一般是不会混着用的,位段有很多的不确定性,所以我们在使用的时候一定要谨慎。

例子:

structB{char a :3;char b :4;char c :5;char d :4;};//char类型在位段存储中每次开辟一个字节intmain(){structB b ={0};
    b.a =10;
    b.b =12;
    b.c =3;
    b.d =4;

​    return0;}
  • 位段占据内存的规则在这里插入图片描述
  • 位段数据在内存中的存储在这里插入图片描述
  • VS调试展示内存在这里插入图片描述 这些可以说明,在VS下
  • 位段开辟内存是按照成员变量的类型开辟空间的,当开辟的空间不够时,才会去增加1个对应类型大小的空间
  • 位段在内存中存储的方式是小端存储,由低地址向高地址存储数据
  • 分配方式是从右向左,从一个bite位的最低位开始存入数据。
  • C语言并没有规定这些规则,这些规则适用于VS编译器,不同的平台产生的效果是不同的,所以它是不支持跨平台的。

位段的跨平台问题

  1. int位段被看作有符号数还是无符号数是不确定的。
  2. 位段中最大位的数目不确定。(16位机器最大16,32位机器最大32)当我们把一个成员变量所占bite位写成27,在16位机器会出现问题。 数据的顺序不变,接收的顺序不同。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义. 如果数据传输到不同平台的顺序相同,而分配和读取的方向不同,这明显是不对的
  4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳第一个位段剩余部分,是舍弃剩余的位还是利用,这是不确定的。总结:

位段可以达到和结构体相同的作用,而且可以更好的节省空间,但是有跨平台性的问题存在。

位段的应用

在这里插入图片描述

  • 使用位段式的结构合理的利用空间,将传输的数据分块给出固定的大小,减少数据的传输,提高数据传输的效率。

2.枚举

枚举顾名思义就是 一 一列举
把可能的取值 一 一 列举。
比如我们现实生活中:

一周的星期一到星期日是有限的7天,可以一 一例举。
性别有:男、女、保密,也可以一 一列举。
月份有12个月,也可以一 一例句。
这里就可以使用枚举了。

枚举类型的定义

enumColor//颜色{
    RED,
    GREEN,
    BLUE
};enumDay//星期{
    MON,
    TUES,
    WED,
    THUR,
    FRI,
    SAT,
    SUN
};enumSex//性别{
    MALE,
    FEMALE,
    SECRET
};

以上定义的enume Color,enum Day,enum Sex都是枚举类型。

  • 结构体大括号内的变量叫:结构体的成员变量
  • 枚举的大括号内是:枚举的可能取值也叫“枚举常量

因为它是常量,在定义枚举的大括号外,无法给它赋值。

在这里插入图片描述

这些可能取值都是有值的,默认从0开始,一次递增1

enumcolor{
    RED,
    GREEN,
    BLUE
};intmain(){printf("%d\n", RED);printf("%d\n", GREEN);printf("%d\n", BLUE);return0;}

在这里插入图片描述

在定义的时候也可以赋初值

enumcolor{
    RED=1,
    GREEN=4,
    BLUE
};intmain(){printf("%d\n", RED);printf("%d\n", GREEN);printf("%d\n", BLUE);return0;}

在这里插入图片描述

一个枚举类型的大小只有四个字节,每次取出的值为枚举的可能取值,它们不是同时在枚举类型中存储,一次只调用一种可能。(不同编译器下,枚举的大小可能会取不同的值)

enumcolor{
    RED,
    GREEN,
    BLUE
};intmain(){printf("%d\n",sizeof(enumcolor));return0;}

在这里插入图片描述

枚举的优点

我们可以使用#define定义常量,为什么非要使用枚举?

枚举的优点:

  1. 增加代码的可读性和可维护性 > 当使用switch时可以将case后的选项替换为枚举的可能选择
  2. 和#define定义的标识符比较枚举有类型检查,更为严谨。 > #define定义的常量是直接替换掉,而枚举常量是有自己的类型的> 1.> 在这里插入图片描述> 2.> 在这里插入图片描述
  3. 防止了命名污染 > 将枚举常量放在大括号中,对其进行封装防备受到污染。
  4. 便于调试 > 枚举在调试中是可以直接看到的,而#define是直接替换> 在这里插入图片描述
  5. 使用方便,一次可以定义多个常量。

3.联合(共用体)

联合类型的定义

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

例如:

//联合类型的声明union Un
{char c;int i;};//联合变量的定义union Un un;

联合的特点

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

union Un
{char c[5];int i;};intmain(){union Un un;printf("%d\n",sizeof(un));printf("%d\n",sizeof(un.c));printf("%d\n",sizeof(un.i));printf("%d\n",&(un.c));printf("%d\n",&(un.i));return0;}

在这里插入图片描述

  • 这里我们可以看到,不同类型的联合体成员的大小是不同的,但它们的地址却是相同的。这就是特征的表现——共用同一块内存空间。
union Un
{char c;int i;};intmain(){union Un un;
    un.i =0x11223344;
    un.c =0x55;printf("%x\n", un.i);printf("%x\n", un.c);return0;}

在这里插入图片描述

  • 当联合体一个成员的值发生改变会影响到其他成员在该空间的改变
  • 在联合体中的变量调用时最多只能有一个成员变量被调用,否则会使存储的数据变的很混乱。

联合大小得计算

  • 联合的大小至少是最大成员的大小 最少要保证可以存储最大的成员的数据。
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
union Un
{char c[7];//虽然c是个数组,但对齐数是以类型来所的,char类型对齐数为1,c总共占7个字节int i;//int类型对齐数为4};intmain(){union Un un;//默认对齐数为8,最大对齐数为4,取最小值4.printf("%d\n",sizeof(un));//最大的成员为c占7个字节,不是最大对其数4的整数倍,取最大对齐数的整数倍8,输出结果为8//而多余的一个空间是被浪费掉的,访问不到,非要访问可以使用数组,越界访问。return0;}

在这里插入图片描述

使用联合体判断大小端

在之前博客数据得存储中,讲到了判断大小端得方法,使用int和char的交换判断
这里我们使用新的方法重新判断

union Un
{int a;char b;};intmain(){union Un un;
    un.a =0x1;int flag = un.b;if(flag ==1)printf("小端\n");elseprintf("大端\n");return0;}

在这里插入图片描述

标签: c语言 c++

本文转载自: https://blog.csdn.net/m0_52094687/article/details/127025404
版权归原作者 榶曲 所有, 如有侵权,请联系我们删除。

“【C语言】自定义类型—位段、枚举、联合体”的评论:

还没有评论