自定义类型(结构体,枚举,联合)(上)

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

二.位段


2.1 位段的介绍


位段的声明和结构体是大同小异的,仅有两个地方不一样:


1、位段的成员必须是int ,unsigned int 或signed int ,char等整型家族。


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


比如:


1669215223920.jpg


我们可以看到,A的大小是8个字节,64bit,而不是47bit,近似6个字节,所以说明位段有它独特的内存开辟方式。


注意:冒号后面的数字表示几个bit,而不是字节。


2.2 位段的内存分配


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

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


通过上述,我们发现位段是一次一个字节,或者4个字节开辟的。


我们再看以下代码:


1669215248199.jpg


在这里我们首先要注意冒号后面的数字(bit)不能大于它的类型。其次我们看到S的大小是3,如果把S里面的所有bit加起来恰好是16bit,也就是两个字节,但是出现了3,说明:


说明中间浪费了一个bit位,因为按照不浪费的形式是两个bit位就够了,但是放完_b之后只剩一个bit不够_c的5个bit,所以又开辟,但是那一个bit浪费了。


2.3 位段的截断


位段的类型是可以赋值的,但是由于我们设置了bit限制,所以这里对于如何处置这些值是不清楚的。我们可以分析以下代码:

struct S
{
  char _a : 3;
  char _b : 4;
  char _c : 5;
  char _d : 4;
  //冒号后面的数字不能超过类型的大小
}s;
int main()
{
  s._a = 10;
  s._b = 12;
  s._c = 3;
  s._d = 4;
  return 0;
}


很明显,这里的10转化为二进制是1010,需要4个bit位,而位段限制只有3个bit可以给,所以我们要深入到内存的存储来看一下vs是如何安排的。


1669215274778.jpg


我们可以调试验证一下是不是不这样。


1669215285519.jpg


的确如我们所推的那样,会发生截断。


2.4 位段的跨平台问题


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

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

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

4、当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,尚不确定。跟结构体相比,位段可以达到同样的效果,可以很好的节省空间,但是跨平台的问题存在。


2.5 使用位段需要注意的问题


1、冒号后面表示的是bit

2、冒号后面的数字(bit)不能超过类型的大小

3、如果不够,会直接新开辟,而不是会利用剩下的bit

4、位段开辟是以一次一个或者4个字节开辟的

5、位段会发生截断。


三.枚举


3.1 枚举的介绍


枚举,就是列举,比如我们生活中星期一到星期日可以一一列举,365天的每一天也可以一一列举。


简单的使用:

enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex//性别
{
MALE,
FEMALE,
SECRET
};
enum Color//颜色
{
RED,
GREEN,
BLUE
};


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


{}中的内容是枚举类型的可能取值,也叫枚举常量。枚举默认第一个从0开始,一次递增1.当然在定义的时候可以赋初始值。比如:

enum Color
{
  Red = 1,
  Green=2,
  Blue=5,
  yellow=7
};

这些都是可以的。


3.2 枚举的使用


1669215346887.jpg


3.3 枚举的优点


我们知道#define 可以定义,那么为什么还需要枚举呢?


1.增加代码的可读性和可维护性,比如我们在用switch语句设计分支时,如果用1,2,3,等等来设计选择,那么我们可能不知道意思是怎样的,如果用枚举来替代,代码可读性大大提高。

2.和#define定义的标识符比较,枚举是一种类型,有类型检查,更加严谨。

3.防止了命名污染。

4.便于调试。

5.使用方便,一次可以定义多个常量。


四.联合(共用体)


4.1 联合类型的定义

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


1669215378217.jpg


这里我们发现它的大小是4,我们知道如果是按照结构体来说,大小应该是8,说明联合体的内存管理不同于结构体。


4.2联合的特点


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


1669215388354.jpg


通过这串代码,我们发现它们的地址也是一模一样。这样我们就可以猜想,联合是共用一块空间地址也是一样的。那么联合所占空间大小如何计算呢?


4.3 联合大小的计算


1、联合的大小至少是最大成员的大小。

2、当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。


比如:


1669215403019.jpg


在这里可能有些人可能疑惑第一个联合体Un1中char c[5]不是大小为5个字节,对齐数为5,第二哥联合体Un2中short c[7]不是大小为14个字节,对齐数为14吗?这样的话大小分别应该是5和14啊。这里我们要说一下,这里的两个数组本质上分别是5个char和7个short。所以对齐数还是1和2.


4.4 联合的应用


某度面试题:


设计一段程序,判断当前机器是大端存储还是小端存储。


普通实现:

int check_sys()
{
  int m = 1;
  char n = (char)m;//强制转为char类型,如果是小端则
  //返回1,大端则返回0
  return n;
}
int main()
{
  int ret=check_sys();
  if (ret == 1)
  {
  printf("小端存储\n");
  }
  else
  printf("大端存储\n");
  return 0;
}


联合体实现:


1669215429183.jpg


主要需要诸位注意的是遇到数组怎么判断对齐数。

相关文章
|
3月前
|
Linux C语言 C++
自定义类型——结构体、枚举和联合
自定义类型——结构体、枚举和联合
|
6月前
|
存储 编译器 Linux
自定义数据类型:结构体+枚举+联合
自定义数据类型:结构体+枚举+联合
|
存储 编译器 C语言
自定义数据类型:结构体,枚举,联合
自定义数据类型:结构体,枚举,联合
|
存储 编译器 Linux
自定义类型——结构体,枚举,联合
自定义类型——结构体,枚举,联合
|
编译器 C++
【学习笔记之我要C】自定义类型详解(结构体+枚举+联合)
【学习笔记之我要C】自定义类型详解(结构体+枚举+联合)
296 0
|
11月前
|
编译器 C++
自定义类型:结构体,枚举,联合 (1)
自定义类型:结构体,枚举,联合 (1)
69 1
|
11月前
|
编译器 C++
自定义类型:结构体,枚举,联合
自定义类型:结构体,枚举,联合
|
11月前
|
存储 编译器 C++
自定义类型:结构体,枚举,联合 (2)
自定义类型:结构体,枚举,联合 (2)
61 0
|
11月前
|
存储 安全 编译器
自定义类型:结构体,枚举,联合
自定义类型:结构体,枚举,联合
109 0
|
编译器 C++
自定义类型:结构体、枚举、联合
自定义类型:结构体、枚举、联合
57 0
自定义类型:结构体、枚举、联合
下一篇
无影云桌面