【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. 总结

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

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

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

相关推荐
k09333 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
神奇夜光杯11 分钟前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
Themberfue14 分钟前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
plmm烟酒僧15 分钟前
Windows下QT调用MinGW编译的OpenCV
开发语言·windows·qt·opencv
EricWang135825 分钟前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
测试界的酸菜鱼27 分钟前
Python 大数据展示屏实例
大数据·开发语言·python
我是谁??27 分钟前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
小码农<^_^>29 分钟前
优选算法精品课--滑动窗口算法(一)
算法
羊小猪~~31 分钟前
神经网络基础--什么是正向传播??什么是方向传播??
人工智能·pytorch·python·深度学习·神经网络·算法·机器学习
晨曦_子画36 分钟前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin