【C语言进阶篇】一篇文章让你彻底拿下 位段 枚举 联合!(上)

简介: 【C语言进阶篇】一篇文章让你彻底拿下 位段 枚举 联合!(上)

📋 前言

  🌈hello! 各位宝子们大家好啊,前面一章给大家带来了结构体的深层次 讲解,那么接下来就来到下一章的学习了,铁铁们准备好了嘛?

  ⛳️本期给大家带来的是 位段的内存分配 枚举 联合(共用体)的详细讲解让我们一起学起来把!

  📚本期文章收录在《C语言进阶篇》,大家有兴趣可以看看呐

  ⛺️ 欢迎铁汁们 ✔️ 点赞 👍 收藏 ⭐留言 📝!

💬 位段

  ⛳️一般情况下在书里,结构体的章节过来了之后就是位段(位域)叫法不同而已,说明我们的位段是靠结构体来实现的!

💬 什么是位段

位段的声明和结构是类似的,有两个不同:

  • 1.位段的成员必须是 int、unsigned int 或signed int 。
  • 2.位段的成员名后边有一个冒号和一个数字。(冒号后面的数字不得超过前面类型的大小.)

📚 代码演示:

struct A
{
 int _a:2;
 int _b:5;
 int _c:10;
 int _d:30;
};

⛳️ 这里A就是一个位段类型。那位段A的大小是多少?

  • 会是我们心里想的16个字节嘛?

📑 代码结果:

诶这时你会发现这个结构体的内存对齐计算结构体大小完全不一样啊!为什么大小是这个呢?

  • 就算是按4个整形计算也不可能是8个字节啊
  • 下面我们就来介绍一下位段的内存是如何分配的!

🔥 注:结构体如何计算大小文章链接《结构体的内存对齐》

  ⛳️ 位段位段,说明他是位的截段 那么是什么位呢?答案是 比特位 !,每个数字是占多少个 比特位

  • 大家可以验证一下,这些数字加起来刚好32位
  • 而32个 比特位4 个字节刚好能装下
  • 大家看一下下面这个猜一下是不是我们计算的4呢!
struct B
{
  int _a : 2;
  int _b : 5;
  int _c : 15;
  int _d : 10;
};

📑 代码结果:

哦!的确是这样的。下面我们就来具体看下位段到底是怎么样开辟空间的

💭 位段的内存分配

📜说明:

  • 🌱 位段的成员可以是 intunsigned intsigned int 或者是 char(属于整形家族)类型
  • 🌱 位段的空间上是按照需要以 4 个字节( int )或者1个字节( char )的方式来 开辟 的。
  • 🌱 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

  ⛳️ 这些是什么意思呢?就是我们位段的成员必须是整形家族的,如果我们位段时int 类型的那么就会先开辟4个字节,不够在开辟4个字节这样一直开辟下去, char类型的也是同理!

📚 举个例子:

#include <stdio.h>
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;
}

  ⛳️那么究竟是不是我们这样描述存储的实践一下看看就明白了,假设我们在vs2019 这个平台上是从低向高访问的

  • 并且按照我们分配内存的慷慨性一旦放不下就重新开辟空间!
  • 而我们的位段 是char 类型的说明先开辟一个字节 ,不够在开辟
  • 那么我们大致画一下内存分布并运行查看一下到底是不是这样的?
    🔥 注:vs2019的情况下成员存放是先从右往左用,但是内存开辟是从地地址向高地址开辟

这里我们想象的大致内存分布是这样的,用了3个字节,程序运行看下是不是这样的?

📑 代码结果:

哦!看来在vs这个环境里就是按我们想像的这样开辟空间的我们在验证一下

  • 我们位段的每个成员都存放数据,然后到内存里面看是不是这样存储的
  • 但是每个成员只占他所对应的 比特位 存放
  • 所以一旦存放的内容超过所能存储的内容就会发生截断

位段成员a在内存中占3个字节但是 10 这个数字要存放 4 个字节,所以我们就会截断

  • 10 的二进制位是1010
  • 截断3位就是 010所以我们 a 存放的就是010

我们把存放进去的二进制位转成16进制来看一下!

  • 因为是 16进制 所以 4 个比特位 为一个 16进制

⛳️这里就可以看到按我们这存放的话,转换出来的16进制是 0x 62 03 04 00

  • 我们在vs2019里面调试看一下存放的和我们一步一样!

📑图片展示:

这时就可以看出在vs2019就是按我们想的那样存储的!

  • 即,位段中的成员在内存中(我们在vs是从低地址到高地址存储的)
  • 一旦分配的字节不过够存放下一个成员,会开辟新的字节来存放新成员

注:但是在C语言中从左向右分配,还是从右向左分配标准尚未定义!

注:当第一个位段的剩余的内容无法存储第二个位段时,要开辟新的空间,那之前剩余的空间是否被利用取决于平台,也没有规定.

💻 位段的跨平台问题

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

  1. int 位段被当成有符号数还是无符号数是不确定的。
  2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机
    器会出问题。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是
    舍弃剩余的位还是利用,这是不确定的。
目录
相关文章
|
2月前
|
机器学习/深度学习 C语言
【c语言】一篇文章搞懂函数递归
本文详细介绍了函数递归的概念、思想及其限制条件,并通过求阶乘、打印整数每一位和求斐波那契数等实例,展示了递归的应用。递归的核心在于将大问题分解为小问题,但需注意递归可能导致效率低下和栈溢出的问题。文章最后总结了递归的优缺点,提醒读者在实际编程中合理使用递归。
69 7
|
2月前
|
存储 编译器 C语言
c语言回顾-联合和枚举
c语言回顾-联合和枚举
33 4
|
2月前
|
存储 C语言 C++
深入C语言,发现多样的数据之枚举和联合体
深入C语言,发现多样的数据之枚举和联合体
深入C语言,发现多样的数据之枚举和联合体
|
2月前
|
存储 机器学习/深度学习 编译器
一篇文章,把你的C语言拉满绩点
一篇文章,把你的C语言拉满绩点
15 0
|
3月前
|
存储 C语言
【C语言基础】一篇文章搞懂指针的基本使用
本文介绍了指针的概念及其在编程中的应用。指针本质上是内存地址,通过指针变量存储并间接访问内存中的值。定义指针变量的基本格式为 `基类型 *指针变量名`。取地址操作符`&`用于获取变量地址,取值操作符`*`用于获取地址对应的数据。指针的应用场景包括传递变量地址以实现在函数间修改值,以及通过对指针进行偏移来访问数组元素等。此外,还介绍了如何使用`malloc`动态申请堆内存,并需手动释放。
|
2月前
|
存储 安全 编译器
深入理解C语言中的枚举
深入理解C语言中的枚举
|
2月前
|
存储 编译器 C语言
【C语言】自定义类型:联合与枚举的简明概述
【C语言】自定义类型:联合与枚举的简明概述
|
4月前
|
存储 程序员 C语言
揭秘C语言:这些核心知识你掌握了吗?一篇文章带你突破编程基础,开启高效编码之旅!
【8月更文挑战第22天】C语言作为编程基石,以简洁高效著称,历经数十年仍备受欢迎。本文通过梳理C语言的核心概念,帮助读者深入理解并提升技能。适合各水平读者。基础语法从`main`函数开始,如示例中的“Hello, World!”程序所示。C语言强调头文件包含与语句结尾的分号。变量和数据类型丰富多样,如`int`、`float`、`char`等,合理选择可优化内存使用和性能。指针用于间接访问内存,是C语言的关键特性。控制结构如循环和分支使程序逻辑更灵活。函数支持代码复用与模块化。深入学习还需掌握预处理指令、文件操作等高级特性。通过系统学习与实践,你将能更熟练地使用C语言,构建高效稳定的应用。
71 4
|
4月前
|
存储 编译器 C语言
【C语言篇】自定义类型:联合体和枚举详细介绍
像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。
49 1
|
4月前
|
C语言
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)