当前位置:网站首页>【结构体内功修炼】结构体实现位段(二)
【结构体内功修炼】结构体实现位段(二)
2022-08-05 07:39:00 【Albert Edison】
前言
上一篇文章讲解了 结构体内存对齐,这篇文章讲讲结构体实现位段的能力
1. 什么是位段
位段的声明和结构是类似的,有两个不同:
1、位段的成员必须是 int
、unsigned int
或 signed int
。
2、位段的成员名后边有一个冒号和一个数字。
位段示例
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
A 就是一个位段类型。
那位段 A 的大小是多少?
我们用 sizeof 看一下
为什么是 8 呢?
其实 位段 的 位 是指 二进制位;
int _a : 2
的意思是:_a
只占 2 个 bit 位;
int _b : 5
的意思是:_b
只占 5 个 bit 位;
int _c : 10
的意思是:_c
只占 10 个 bit 位;
int _d : 30
的意思是:_d
只占 30 个 bit 位;
那把所有的 bite 位加起来也就 47 个 bite 位,给 6(48 bit) 个字节完全够了呀!
为什么打印出来的是 8 个字节?也就是 64 个 bit 呢?
2. 位段的内存分配
1、 位段的成员可以是 int unsigned int
、signed int
或者是 char
(属于整形家族)类型
2、位段的空间上是按照需要以 4 个字节( int )或者 1 个字节( char )的方式来开辟的。
3、位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
还是看刚刚这段代码
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
首先,_a
是整型,不管三七二十一,先开辟 4 个字节也就是 32 bit 给它,但是 _a
只需要 2 个 bit 呀,所以拿走 2 bit 以后,还剩 30 bit;
然后 _b
需要 5 bit,所以拿走 5 bit 以后,还剩下 25 bit;
其次 _c
需要 10 bit,所以拿走 10 bit 以后,还剩下 15 bit;
最后 _d
需要 30 bit,但是此时还剩下 15 bit 呀,完全不够,那怎么办呢?此时再单独开辟 4 个字节也就是 32 bit 给 _d
用(上面剩下的 15 bit 就不会再使用了);
所以 sizeof 求大小的时候,也就是 8 字节。
上面解释了 整型 的位段开辟,那如果当结构体的成员是 char 类型呢?
代码示例
struct S
{
char a : 3;
char b : 4;
char c : 5;
char d : 4;
};
首先,a
是 char 类型,不管三七二十一,先开辟 1 个字节也就是 8 bit 给它,但是 a
只需要 3 个 bit 呀,所以拿走 3 bit 以后,还剩 5 bit;
然后 b
需要 4 bit,所以从 5 bit 里面拿走 4 bit 以后,还剩下 1 bit;
其次 c
需要 5 bit,但是此时还剩下 1 bit 呀,完全不够,此时再单独开辟 1 个字节也就是 8 bit 给 c
用,所以拿走 5 bit 以后,还剩 3 bit;
最后 d
需要 4 bit,但是此时还剩下 3 bit 呀,完全不够,那么再单独开辟 1 个字节也就是 8 bit 给 d
用(上面剩下的 3 bit 就不会再使用了);
所以 sizeof 求大小的时候,也就是 3 字节。
我们用 sizeof 看一下
既然学会了位段,那我们再来分析一下下面这段代码
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;
}
上面我们已经计算过了,这个结构体开辟了 3 个字节,然后在主函数里面把这个 s 初始化为 0,这样就意味着,这 3 个字节里面,每一个 bit 位都为 0;
首要为 a 开辟 1 个字节,a 只占其中的 3 bit,假设 a 在 8 bit 中,是从低位向高位使用的,也就是从右向左的方向,现在把 10 赋值给 a,10 的二进制是 1010,但是 a 的空间大小是 3 bit,所以只能存 3 bit,也就是存 010,最高位的 1 省去
b 里面要放 12,12 的二进制是 1100,但是 b 刚好有 4 bit,所以直接放进去,此时还剩下 1 bit,完全不够 c 使用了,那么再开辟 1 字节
c 占 5 bit,现在要把 3 放进去,3 的二进制是 011,但是 c 要占 5 bit 呀,所以前面添 0,也就是放 00011,此时还剩下 3 bit,完全不够 d 使用了,d 占 4 bit 那么再开辟 1 字节
d 占 4 bit,现在要把 4 放进去,4 的二进制是 100,但是 c 要占 4 bit 呀,所以前面添 0,也就是放 0100
此时主函数里面的代码已经走完了,那么内存里面到底存放的是什么呢?
由于二进制不好观看,我们换算成十六进制
那么内存里面到底存的是不是这个呢?我们可以调试看一看
3. 位段的跨平台问题
1、 int
位段被当成有符号数还是无符号数是不确定的。
2、位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机
器会出问题。)
3、位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4、当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是
舍弃剩余的位还是利用,这是不确定的。
总结:跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。
4. 位段的应用
那么位段应用在那些地方呢?比如下面这张网络中经典的 IP 数据报
边栏推荐
猜你喜欢
TRACE32——C源码关联1
After working for 3 years, I recalled the comparison between the past and the present when I first started, and joked about my testing career
Flink学习12:DataStreaming API
学习机赛道加速:请“卷”产品,不要“卷”营销
爬虫之验证码
TRACE32——通用寄存器查看与修改
双向循环带头链表
Redis数据库学习
Why does Mysql fail to create a database
In the anaconda Promat interface, import torch is passed, and the error is reported in the jupyter notebook (only provide ideas and understanding!)
随机推荐
Mysql 死锁和死锁的解决方案
TRACE32——Go.direct
MAYA大炮建模
青苹果论坛重新开放
Algorithm Supplements Fifteen Complementary Linked List Related Interview Questions
ARM Cortex-M上的Trace跟踪方案
执子之手,与子偕老。你同意么?
Vulnhub靶机:HA_ NARAK
Illegal key size 报错问题
RNote108---Display the running progress of the R program
高效使用数码相机的诀窍
Discourse 清理存储空间的方法
字符串提取 中文、英文、数字
window.open 全屏展示
TRACE32——List源代码查看
Jmeter永久设置中文界面
Flink学习12:DataStreaming API
谷歌零碎笔记之MVCC(草稿)
YOLOv3 SPP理论详解(包括CIoU及Focal loss)
国家强制性灯具安全标准GB7000.1-2015