【C语言】使用结构体实现位段

一、位段

前面我们学习了结构体,位段的声明和结构体是一样的,其区别如下:

1、位段的成员必须是int 、unsigned int 、signed int 、在C99中位段的成员的类型也可以选择其他类型。

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

如下:

那么这几个变量后面的数字表示啥意思呢?会不会是表示其二进制的位数呢?

我们继续往下分析

二、位段的内存分配

1、位段的分配规则:

(1):位段的成员可以是int , unsigned int , signed int ,char类型。

(2):位段在空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的,比如说 整型int的话,那么一次性就开辟4个字节,是字符型(char)那么一次性就开辟1个字节。

(3):如果开辟空间不足的话,那么才会再次开辟对应的空间,不会一次性就开辟完所有的空 间 ,而是一个一个开辟的。

下面我们通过一个练习来了解位段

练习1:

那么位段在内存中的空间是如何开辟的呢?

我们先来看第一个成员,第一个成员是char型吗,那么首先会开辟一个字节的空间,然后将a存放进去,然后我们的a的后面是3,那么其为3个bit位,那么其是如何放进内存的呢?是从左边开始放还是从右边呢?

位段从开辟空间的左边还是右边开始存放,C语言中并没有规定,那么就是说其从左边和右边开始使用都是有可能的。

那么我们当前使用的vs2022的环境是从右边开始使用的, 那么我们按照这个逻辑去看这个位段是怎么存放。

首先我们先存入a,其占3个bit位,然后我们再看第二个成员,其占用4个bit位,然后我们现在还有5个bit的位置,那么足够其存放,那么其就从右边往左边接着存放。

然后我们看第三个成员,其占用5个bit位,但是现在只有一个bit位了,那么空间就不够了,那么此时就会开辟新的空间,然后又因为第三个成员是char字符型,那么就会开辟一个字节的空间。但是此时第三个成员是接着使用前面多的那个bit的空间使用,还是在新开辟的空间使用呢?

这个在C语言中也没有明确的规定。

所以两种可能完全取决于我们的编译器。

我们可以使用sizeof关键字查看当前的位段是多少字节的来判断我们的vs2022是那种方法:

1、如果是接着使用剩下的bit位的话那么这个位段的大小:

第三个成员存放后,那么此时开辟的第二个字节的空间还有4个bit的空间。

然后我们看第四个成员,其是4个bit位,那么剩下的刚刚好足够存放,那么此时的大小应该为2 个字节。

2、如果是从新开辟的位置开始

那么其再第四个成员的时候,因为新开辟的空间还有3个bit位,那么我们就需要再开辟一个字 节那么此时的大小就为3字节了

最后我们看程序的运行结果:

可以看到其得到的结果是方法二的存放方式。

为了证明我们的猜想是正确的,我们进一步验证,我们可以对这个位段进行赋值。

如下:

我们首先创建了一位段S,然后将其初始化为0,然后我们对这个位段的成员进行赋值,首先就是第一个成员对其赋值10,那么其二进制为1010,然后其在位段中只是占了3个bit位,那么此时就会发生截断,然后其变成010,然后存进存储,然后我们看第二个成员,其赋值为4,其二进制为1100,然后其是4个bit位,那么接着存入,然后我们看第三个成员其是5个bit位,其二进制为 00011,此时需要开辟下一个字节,然后从下一字节开始存入,那么此时第一个字节存放的内容为:01100010,然后我们看第四个成员,其要使用4个bit位,那么需要再开辟一个字节的空间了,然后此时第二个字节中存放的内容为:00000011,第三个字节存放的内容为:00000100。

下面我们查看内容看看:

可以看到在内存中的存放确实如我们说的这样。

那要是遇到不同的平台,这时候该怎么办呢?下面我们来看看这个问题。

三、位段的跨平台问题

位段虽然可以省空间,但是其存在着很大的跨平台问题,可移植性低,这是因为在C语言中,位段没有一个标准,导致在不同的编译器中,其实现的结果可能是不一样的。下面我们看看其主要的问题:

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

2、位段中最大位的数目不能确定,因为在32位的机器中,int的大小是2字节,而在64位机器中的大小是4字节,那么就 会出问题了。

3、位段中的成员在内存中的存入顺序可能不同,因为没有标准,其可能会从左边开始往右边存 入,这样也会导致数据的结果是不同的。

4、当一个结构包含两个位段,第二个位段成员比较大,无法容纳第一个位段成员比较,那么是舍 弃剩下的位还是,还是继续使用,这个也是没有一个标准的。

所以,我们在使用位段的时候,一定不要跨平台使用,不过其比较省空间。

四、位段的应用

下图是⽹络协议中,IP数据报的格式,我们可以看到其中很多的属性只需要⼏个bit位就能描述,这⾥ 使⽤位段,能够实现想要的效果,也节省了空间,这样⽹络传输的数据报⼤⼩也会较⼩⼀些,对⽹络 的畅通是有帮助的。

五、位段使用的注意事项

通过上面的学习,我们知道位段的几个成员是可能存在共有同一个字节的情况的,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置是没有地址的,因为在内存中地址是以字节为单位的,然而bit是没有地址的。

所以我们不要对位段的成员使用取地址&。

那么我们就没办法直接对取进行输入值了,也就是没办法直接对其使用scanf关键字了,那么我们实在是需要从就键盘对其赋值呢?是不是就没办法了?有的,有的。

下面我们先看一个错误的示范:

可以看到此时编译器都直接报错了,这是因为这里b只使用了5个bit位,没有单独使用使用一个字节位,所以这个&sa.b的方法是错误的。

我们来看看正确的写法:

这里我们创建了一个整型变量b,那么我们可以对这个整型变量进行&了,那么就可以先对这个整型变量b进行赋值,然后再将这个值赋个位段的成员即可。

相关推荐
冯汉栩11 小时前
Swift Control View,Label渐变颜色(源码)
开发语言·ios·swift
白狐_79812 小时前
408 数据结构|线索二叉树两题详解:先序线索化后的空链域 + 中序前驱/后继判断
c语言·数据结构·链表
从小就看凹凸曼^o^12 小时前
Python基础5 - 字典与集合:(1)字典
开发语言·python
GeekZHR12 小时前
C语言指针进阶补充6:动态内存管理、mem系列内存函数、复杂指针声明,一次补齐指针的“三大盲区“
java·c语言·算法·指针
Herbert_hwt12 小时前
第七章 Java深入理解枚举类型
java·开发语言·算法
侧耳倾听11112 小时前
java 日志框架简介
java·开发语言
zlinear数据采集卡12 小时前
数据采集卡从入门到精通(9):分辨率与精度——16位卡不等于1/65536的精度
开发语言·数据库·fpga开发·开源·c#
全栈技术负责人13 小时前
解密 MCP(Model Context Protocol):大模型时代的“Type-C”总线与三驾马车架构深度解析
开发语言·ai·架构
丰锋ff13 小时前
1.7在Qt窗口中添加右键菜单
开发语言·qt
Titan202413 小时前
Linux网络学习:套接字、UDP的封装与应用
linux·服务器·开发语言·网络·c++