『C语言进阶』自定义类型详解(二)

简介: 『C语言进阶』自定义类型详解(二)

『C语言进阶』自定义类型详解(一):https://developer.aliyun.com/article/1392700

二、位段

2.1 什么是位段

  1. 位段的成员必须是int、unsigned int或者signed int(还可以是char类型)
  2. 位段的成员后边有一个冒号和一个数字
#include<stdio.h>
struct A
{
  int a : 2;//a需要2个比特位
  int b : 5;//b需要5个比特位
  int c : 10;//c需要10个比特位
  int d : 28;//d需要28个比特位
};//这就是一个位段
int main()
{
  printf("%d\n", sizeof(struct A));
  return 0;
}

运行结果:

8

首先因为a是int类型,所以开辟了4个字节(32个比特位)的空间,a需要2个比特位,还剩30个比特位,刚好b需要5个比特位,就给b,还剩下25个比特位,刚好c需要10个比特位,给c后还剩15个比特位,而d需要28个比特位,还剩下的15个比特位不够,d就只能再开辟一个int类型空间即四个字节,所以一共是8个字节。

这时候相信铁汁们有个这样的疑问?:

那个还剩下来的15个比特位怎么用的?

#include<stdio.h>
struct S
{
  char a : 3;
  char b : 4;
  char c : 5;
  char d : 4;
};
int main()
{
  printf("%d\n", sizeof(struct S));
  return 0;
}

运行结果:

3

所以在这里我们可以猜测VS2022,上一次开辟的空间剩下的不够时,是被遗弃了,并没有再次使用,直接用新开的空间。

2.2 位段的内存分配

  • 位段的成员可以是 int 、unsigned int、signed int 或者是 char (属于整形家族)类型
  • 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
  • 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
struct S
{
  char a : 3;
  char b : 4;
  char c : 5;
  char d : 4;
};
int main()
{
  struct S s = { 0 };
  s.a = 10;
  s.b = 12;
  s.c = 3;
  s.d = 4;
  return 0;
}

2.3 位段的跨平台问题

  • int 位段被当成有符号数还是无符号数是不确定的。
  • 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。
  • 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  • 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

总结:

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


三、枚举

枚举顾名思义就是列举,把可能的取值列举。(枚举是一个常量)

例如:

一周是从周一到周日,是有限的,可以一一列举

三原色,也可以一一列举

3.1 枚举类型的定义

#include<stdio.h>
enum day//星期
{
  Mon,
  Tues,
  Wed,
  Thir,
  Fri,
  Sta,
  Sun
};
enum Sex//性别
{
  MALE,
  FEMALE = 3,
  SECRET
};
enum Color//颜色
{
  RED,
  GREEN = 89,
  BLUE = 78
};
int main()
{
  enum Day a = Sun;
  printf("%d\n", Mon);
  printf("%d\n", Tues);
  printf("%d\n", Wed);
  printf("\n%d\n", MALE);
  printf("%d\n", FEMALE);
  printf("%d\n", SECRET);
  printf("\n%d\n", RED);
  printf("%d\n", GREEN);
  printf("%d\n", BLUE);
  return 0;
}

运行结果:

0
1
2
0
3
4
0
89
78

以上定义的enum Day,enum Sex,enum Color都是枚举类型,{}中 的内容都是枚举类型的可能取值,也叫枚举常量

这些可能取值都是有值的,默认从0开始,依次加1,也可以在定义时赋值初值

3.2 的使用

enum Color
{
     RED=1,
     GREEN=2,
     BLUE=4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值

注意:

  • 枚举是一个常量,在定义枚举的时候(无论有没有赋值),不可以对可能取值的值进行改变,例如:Mon=3;(如果想让值发生改变,只能在定义枚举的时候进行赋值改变)

3.3 枚举的优点

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

四、联合(共同体)

4.1 联合体的定义

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

#include<stdio.h>
union Un
{
  char c;
  int i;
};
int main()
{
  union Un u;
  printf("%d\n", sizeof(u));
  printf("%p\n", &u);
  printf("%p\n", &(u.c));
  printf("%p\n", &(u.i));
  return 0;
}

运行结果:

4
000000406BD4F784
000000406BD4F784
000000406BD4F784

起始地址是一样的,共用一块地址,所以是4个字节

4.2 联合体的特点

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

习题:判断当前计算机的大小端存储:

低位放在低地址的是小端,地位放在高地址的是大端

常规写法:

#include <stdio.h>
int cheak_sys()
{
  int a = 1;//00 00 00 01(16进制)
  return *((char*)&a);
}
int main()
{
  int ret = 0;
  ret = cheak_sys();
  if (ret == 1)
    printf("小端\n");
  else
    printf("大端\n");
  return 0;
}

用联合的方法写:

#include <stdio.h>
int cheak_sys()
{
  union Un
  {
    char c;
    int i;
  }u;
  u.i = 1;
  return u.c;
}
int main()
{
  int ret = 0;
  ret = cheak_sys();
  if (ret == 1)
    printf("小端\n");
  else
    printf("大端\n");
  return 0;
}

运行结果:

小端

4.3 联合体大小的计算

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

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

(和结构体一样)但是注意起始地址是一样的

#include <stdio.h>
union Un1
{
  char c[5];
  int i;
};
union Un2
{
  short c[7];
  int i;
};
int main()
{
  printf("%d\n", sizeof(union Un1));//8
  printf("%d\n", sizeof(union Un2));//16
  return 0;
}

本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位铁汁们的支持。文章有任何问题可以在评论区留言,小羊一定认真修改,写出更好的文章~~

相关文章
|
4月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
16天前
|
存储 编译器 Linux
C语言——自定义类型
C语言——自定义类型
|
19天前
|
存储 编译器 C语言
【C语言】自定义类型:联合与枚举的简明概述
【C语言】自定义类型:联合与枚举的简明概述
|
2月前
|
存储 编译器 C语言
【C语言篇】自定义类型:联合体和枚举详细介绍
像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。
40 1
|
2月前
|
存储 安全 编译器
C语言自定义类型
C语言自定义类型
31 10
|
4月前
|
编译器 测试技术 C语言
【C语言】:自定义类型:结构体的使用及其内存对齐
【C语言】:自定义类型:结构体的使用及其内存对齐
61 7
|
4月前
|
编译器 C语言 C++
【C语言基础】:自定义类型(二) -->联合和枚举
【C语言基础】:自定义类型(二) -->联合和枚举
|
4月前
|
编译器 C语言
【C语言基础】:自定义类型(一)--> 结构体-2
【C语言基础】:自定义类型(一)--> 结构体
|
4月前
|
编译器 Linux C语言
【C语言基础】:自定义类型(一)--> 结构体-1
【C语言基础】:自定义类型(一)--> 结构体
|
4月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
43 0