【C语言】详解结构体(下)(位段)

文章目录

  • 前言
  • [1. 位段的含义](#1. 位段的含义)
  • [2. 位段的声明](#2. 位段的声明)
  • [3. 位段的内存分配(重点)](#3. 位段的内存分配(重点))
    • [3.1 存储方向的问题](#3.1 存储方向的问题)
    • [3.2 剩余空间利用的问题](#3.2 剩余空间利用的问题)
  • [4. 位段的跨平台问题](#4. 位段的跨平台问题)
  • [5. 位段的应用](#5. 位段的应用)
  • [6. 总结](#6. 总结)

前言

相信大部分的读者在学校或者在自学时结构体的知识时,可能很少会听到甚至就根本没有听过一个知识点,那就是位段。

本文就给大家揭开位段的神秘面纱。🎶💖💖

1. 位段的含义

位段中的"位",指的是比特位(bit)。也就是说,我们可以通过位段指定变量所占内存空间的大小,而这个单位就是bit。

可能上面这么讲,你还是很疑惑。那我就举个例子:

假如我现在有个整型变量i,我知道它未来的赋值情况只可能是0,1,2,3这四个整数。那如果我们直接用4个字节去存储,未免有点浪费了。仔细再想一下,0,1,2,3,这四个数字,我有两个比特位就可以完整的表示出来了,没有必要用32个比特位。

那看到这里,有的读者读者就会说,位段这么好,那我是不是可以随意使用。答案我们在后面揭晓!

2. 位段的声明

位段的声明与结构体相类似。不过需要注意以下几点:

1.位段的成员必须得是int、unsigned int、signed int、char数据类型,在C99的标准中了可以是其他的数据类型。

  1. 位段成员名后必须得有冒号和一个数字。

比如:

c 复制代码
struct S
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

这个变量名有个下划线,不是硬性规定,大家可以按照自己的习惯来编写。

那么此时,S就是一个位段类型。

那在这里我们就得思考一个问题了,位段S所占内存空间的大小是多少?

这里我先给出结果,大家可以慢慢思考。

3. 位段的内存分配(重点)

根据上面给出的结果,相信不少读者就会产生疑惑了。那接下来,我们就来聊一聊为什么会是这样的。

其实有个我上面讲过的知识点,可以作为我们寻求问题答案的突破口:

  • 位段成员必须得是int、signed int、unsigned int 、char的数据类型。
  • 位段的空间上是按照以4个字节(int)或者是1个字节(char)的方式来开辟的。
  • 位段涉及到很多不确定的因素,位段是支持跨平台使用的,注重可以移植性的程序应该避免使用位段。

那接下我有一段代码,给大家讲一讲位段在内存中是如何开辟空间的。

c 复制代码
#include<stdio.h>

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

int main()
{
	//一个例子
	struct S s = { 0 };
	s._a = 10;
	s._b = 12;
	s._c = 3;
	s._d = 4;
	
	//空间是如何开辟的

	return 0;
}

3.1 存储方向的问题

位段在存储数据时,是先申请1个字节或4个字节的空间,等到这些字节空间放满时才会申请下一个字节(一样的大小)的空间。

提醒:本文以4个字节的大小来开辟内存。

这样就不得不思考一个问题,我们申请到的内存空间是从左边开始存放比特位呢还是从右边开始呢 ?答案是:不确定。

那既然是不确定我们就假设从右边 开始吧,请看图解

3.2 剩余空间利用的问题

当我们向内存存放到第四个变量_d时,发现剩下的空间不够存放_d了,此时编译器会再开辟一块4个字节大小的空间,用来继续存放剩余的成员。

可此时我们又得思考一个问题了,那就是之前还剩下一部分内存空间没有使用,是接着使用呢还是直接在新开辟的内存区域中使用呢 ?答案是:不确定

那我们就假设从直接在新开辟的内存区域中存放数据。

根据编译器(以VS为例)读取数据的方式(每4个bit算作一个16进制数),我们可以猜到它在内存中存储的样子:

那此时应该是:00 00 01 B2 00 00 00 04 (VS的采用的时小端存储模式)

可以看到,我们的假设是成立的。在VS的环境下,确实是从申请空间的右边开始存放,并且当还有剩余的内存空间时,不会再继续使用,而是在新开辟的空间上使用。

讲到这里,相信你已经对位段的内存空间分配已经有了个清楚的认识。

4. 位段的跨平台问题

在上面我们讲了位段的不确定性,正是这些不确定性造成了位段的跨平台问题。

  1. int 位段被当成有符号数还是⽆符号数是不确定的。
  2. 位段中最⼤位的数⽬不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会出问题。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配,标准尚未定义。
  4. 当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是弃
    剩余的位还是利⽤,这是不确定的。

5. 位段的应用

我们学会了位段该如何使用,那我们不妨在了解一下,位段在我们实际生产生活中时如何使用的。

一个最典型的例子,网络各种协议的封装:

后面的那些数字,就是使用位段才能产生效果。那至于为什么会是这样子的,这里就请各位读者下来自己去了解了。

6. 总结

我们在之前讲过了结构体的内存对齐,这是一种用空间换取时间的一种做法。而在本文的位段,则是用时间来换取了空间。二种不同的策略,希望读者们能够自己慢慢领会。

最后,如果觉得本文写的还不错的话,请不要吝啬你们手中的赞哦!!!💖💖💖

学习很难,但坚持一定很酷。😊

相关推荐
m0_480227706 分钟前
计算机基础知识总结(八股文--计算机网络、操作系统、数据库、c++、数据结构与算法)
java·数据结构·数据库·c++·计算机网络·mysql·算法
知识分享小能手21 分钟前
R 语言学习教程,从入门到精通,R 绘图 散点图(25)
大数据·开发语言·数据库·学习·数据分析·r语言·统计学
_Jxyz35 分钟前
C++ 异步编程(std::async、std::future、std::promise)
开发语言·c++
hxj1991081437 分钟前
如何自己通过java实现一个rpc框架?简单例子
java·开发语言·rpc
卡戎-caryon1 小时前
【C++】13.特殊类的设计
java·开发语言·c++·算法
沙丁鱼意大利面1 小时前
JS生成随机数
开发语言·javascript·ecmascript
OKkankan2 小时前
数据在内存中的存储
java·c语言·开发语言·数据结构·c++·算法
小鱼在乎2 小时前
贪心算法---K次取反后最大化的数组和
数据结构·算法·贪心算法
No.Ada2 小时前
字节跳动-生活服务-java后端-一面
java·开发语言·生活
yttandb2 小时前
《重生到现代之从零开始的C语言生活》—— 指针5
c语言·生活