网站制作学什么软件,广告设计创意,网站建设行业分析,百度公司结构体相关知识可以先看看这篇文章 —— 链接
一、什么是位段 位段的声明和结构是类似的#xff0c;有两个不同#xff1a; 位段的成员必须是 int、unsigned int 或signed int位段的成员名后边有一个冒号和一个数字
在下面#xff0c;我分别写了一个结构体和一个位段… 结构体相关知识可以先看看这篇文章 —— 链接
一、什么是位段 位段的声明和结构是类似的有两个不同 位段的成员必须是 int、unsigned int 或signed int位段的成员名后边有一个冒号和一个数字
在下面我分别写了一个结构体和一个位段注意看位段的写法和结构体有什么不同
//结构体
struct A {int a;int b;int c;int d;
};
//位段
struct B{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
};然后我们sizeof去计算一下这个结构体的大小
printf(结构体大小%d\n, sizeof(struct A));
printf(位段大小%d\n, sizeof(struct B));可以看到结构体的大小是16位段是8二者为何会存在区别呢原因在于这个: 2吗
那根据位段后面的这些数字我们可以初步去断定可能大小是这些数组的总和再转换为字节的。计算一下可以知道为47b在内存中1B 8b要存下这个47个比特位的话应该6个字节就够了但是结果为什么是8呢我们不得而知 学习了位段的相关知识后你就知道了 二、位段的内存分配
首先来科普一下位段的相关知识
位段的成员可以是 int unsigned int signed int 或者是 char 属于整形家族类型位段的空间上是按照需要以4个字节[int]或者1个字节 [char] 的方式来开辟的。位段涉及很多不确定因素位段是不跨平台的注重可移植的程序应该避免使用位段 那从上面我们就可以提取出一些信息知道了对于整型而言会开辟出4个字节的数据给到位段作为存放那接下去呢我们就来分析一下这个位段仔细观察可以得知每个成员都是整型那首先开辟出32个比特位 _a占了2个比特位还剩下【30b】_b占了5个比特位还剩下【25b】_c占了10个比特位还剩下【15b】_d占了30个比特位但是剩下的【15b】不够用了此时编译器会继续开辟出4B也就是32b的空间来存放 所以最后的结果就是4 4 8B
struct B{//4Byte - 32bitint _a : 2; //30int _b : 5; //25int _c : 10; //15//4Byte - 32bitint _d : 30;//4 4 8
};看了我上面的这样计算你一定会有这些疑问 第一次是32b用剩后的【15b】去哪儿了呢 _d使用的是【15b】 后面开辟出来的32b还是只用到后面的32b呢 难道所有平台都是这样吗有没有不一样的计算方法
上面是很多同学在课后提出来的疑问关于这些你在看完了我下面的分析后就会明白了
内存图分析位段分布 接下去我就通过对位段进行分析然后观察内存分布来揭晓上面究竟是如何计算的。 为了方便期间这里换一组位段但是换汤不换药
struct S
{char a : 3;char b : 4;char c : 5;char d : 4;
};int main(void)
{struct S s { 0 };s.a 10;s.b 12;s.c 3;s.d 4;return 0;
}首先来看一下存放这个位段需要的字节数。可以看到这个位段中的每个成员都是char类型的所以编译器会首先为其分配一个字节的空间然后随着变量的存入最终是需要三个字节 然后我们来逐一分析一下 刚才说了这个位段在内存中需要开辟三个字节这些变量要怎么存呢首先看到变量a占了3个比特位那是从左边的三位开始放还是右边的三位呢总不可以从中间开始放吧 那我们假设一下从右边往左边放那么a放完后就是b占4个比特位但是放c的时候就放不下了所以需要在开辟1个字节的空间此时d再来放的话也放不下了所以也要再开辟1个字节 最后也就需要3个字节的空间 【详细分析如下】
接下去我们就根据main函数中对位段各变量的初始化来看看位段在内存中的分布情况a的初始值为10不过这是十进制转换为二进制形式的话就是[1010]转看位段这里a变量的是占了3位所以会截断成010将它放到第一个字节处的右边3个比特位处接下去是b初始值为12转换为二进制形式的话就是[1100]而b在内存中也刚好是占4个比特位的大小刚好第一个字节处还可以放得过所以继续顺位放置然后是c,初始值为3转换为二进制形式的话就是11但是c在内存中也占5个比特位的大小所以要在前面做一个扩充便为[00011]但是第一个字节放不下了上面放了【3】【4】【7】只剩下1个比特位那我们考虑再开一个字节的空间为了保持连续性就直接把这个5个比特位的数据放到第二个字节的右边最后的是d初始值为4转换为二进制形式的话就是100不过d在内存中也占4个比特位的大小所以要在前面补上一个0即为[0100]但是第二个字节也放不过了只剩三个比特位了所以我们考虑再开一个字节的空间然后放这个d 上面只是我假设的编译器执行思维不过真正是怎样的我们还是要求证一下 那要怎么求证呢这个很简单既然这些变量都是存放在位段中那我们刚才都算出所存放的二进制形式了。对于内存中的地址一般我们看到都是十六进制所以可以考虑把这些二进制4个为一组转换为十六进制看看 01100010即为——0x6200000011即为——0x0300000100即为——0x04 而在内存中左边是低地址右边是高地址所以我们看到的应该是62 03 04 cc。来通过【内存】观察一下吧
可以看到确实和我们分析得是一模一样✌ 看完了上面这个相信你对一开始的那个位段如何去进行求解的整个流程应该是非常清楚了留给读者自己的分析观察
三、位段的跨平台问题 接下去我们再来讲讲有关位段的跨平台的问题 int 位段被当成有符号数还是无符号数是不确定的位段中最大位的数目不能确定。16位机器最大1632位机器最大32 假设我们将位段中一个变量所占大小设置为30即占30个比特位那么它在32为机器上是没问题的但是放到早期的16位机器上去的话可能连编译都编不过因为根本存放不下 位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义 刚才我分析的时候假设的是从右往左进行分配但是呢这在其他平台上可能又是不一样的了 当一个结构包含两个位段第二个位段成员比较大无法容纳于第一个位段剩余的位时是舍弃剩余的位还是利用这是不确定的 这也就是我们一开始纠结的【15】到底还用不用的问题这里给出解答还是不确定取决于平台 总结跟结构相比位段可以达到同样的效果但是可以很好的节省空间但是有跨平台的问题存在 这可能还有的老铁不太理解举个例子假设结构体A中的这个变量a只可能有【0】【1】【2】【3】这四种取值那么只需要2个比特位就可以表达这四个数字了即【00】【01】【10】【11】那我们便可以使用位段来是实现:2但若是放在普通结构体中的话就只能是一个整型4个字节32个比特位的大小这也就浪费了很多的空间同理若是变量b也只有5种表示形式的话5个比特位就够了c、d也是一样。那么这个时候位段就派上用场了若是使用结构体的话就会浪费掉很多的空间。所以我们前面在看的时候结构体所占的空间大小是16B而位段只有8B 四、位段的应用 清楚了位段的相关知识和使用后可能还是有同学比较迷惑这个位段到底是用来干嘛的有什么实际应用场景吗我们来看看 比方说这里有个IP数据包有学习过《计算机网络》相关知识的读者应该都很清楚【不了解可以看看网络层知识点汇总】我们平常在网络上和别人互相聊天的时候所发送的消息并不是直接在网络链路上进行传送的而是会将其封装到一个数据包中它叫做IP数据包例如我们所发送的呵呵只是里面的一个数据部分还存在其他很多的字段这些字段都占有各自的字节数其实对于这些字节数来说就是使用【位段】来实现精准地控制好每个字段需要多少字节数就不会造成浪费的现象了 五、总结与提炼 最后来总结一下本文所学习的内容 在本文中我们首先讲到了位段的相关概念知道了原来使用结构体还可以实现位段不过在看了二者的大小后却产生了疑惑为什么位段所占的大小是这些呢在清楚了位段在内容中的相关分布后我带着读者一步步分析了位段中的成员数据到底是怎么一个个存放到内存中的也通过VS中的【内存】验证观察了我们的分析结果是正确的然后便说道了位段这个东西其实具备很大的不确定性因为它存在跨平台的问题在不同平台下实现的机制可能不同所以就会导致最后的位段大小会不一致最后也说道了位段的作用以及其实际的应用场景让读者学以致用 以上就是本文要介绍的所有内容感谢您的阅读如果觉得有帮助的话可以给个三连哦❤️❤️❤️