C语言位域(位段)详解

news2024/11/27 20:25:29

有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可。例如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二进位。正是基于这种考虑,C语言又提供了一种叫做位域的数据结构。

在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。请看下面的例子:

struct bs{
unsigned m;
unsigned n:4;
unsignedchar ch:6;
};

:后面的数字用来限定成员变量占用的位数。成员 m 没有限制,根据数据类型即可推算出它占用 4 个字节(Byte)的内存。成员 n、ch 被:后面的数字限制,不能再根据数据类型计算长度,它们分别占用 4、6 位(Bit)的内存。

n、ch 的取值范围非常有限,数据稍微大些就会发生溢出,请看下面的例子:

#include<stdio.h>

intmain(){
struct bs{
unsigned m;
unsigned n:4;
unsignedchar ch:6;
} a ={0xad,0xE,'$'};
//第一次输出
printf("%#x, %#x, %c\n", a.m, a.n, a.ch);
//更改值后再次输出
    a.m =0xb8901c;
    a.n =0x2d;
    a.ch ='z';
printf("%#x, %#x, %c\n", a.m, a.n, a.ch);

return0;
}

运行结果:

0xad, 0xe, $

0xb8901c, 0xd, :

对于 n 和 ch,第一次输出的数据是完整的,第二次输出的数据是残缺的。

第一次输出时,n、ch 的值分别是 0xE、0x24('$' 对应的 ASCII 码为 0x24),换算成二进制是 1110、10 0100,都没有超出限定的位数,能够正常输出。

第二次输出时,n、ch 的值变为 0x2d、0x7a('z' 对应的 ASCII 码为 0x7a),换算成二进制分别是 10 1101、111 1010,都超出了限定的位数。超出部分被直接截去,剩下 1101、11 1010,换算成十六进制为 0xd、0x3a(0x3a 对应的字符是 :)。

C语言标准规定,位域的宽度不能超过它所依附的数据类型的长度。通俗地讲,成员变量都是有类型的,这个类型限制了成员变量的最大长度,:后面的数字不能超过这个长度。

例如上面的 bs,n 的类型是 unsigned int,长度为 4 个字节,共计 32 位,那么 n 后面的数字就不能超过 32;ch 的类型是 unsigned char,长度为 1 个字节,共计 8 位,那么 ch 后面的数字就不能超过 8。

我们可以这样认为,位域技术就是在成员变量所占用的内存中选出一部分位宽来存储数据。

C语言标准还规定,只有有限的几种数据类型可以用于位域。在 ANSI C 中,这几种数据类型是 int、signed int 和 unsigned int(int 默认就是 signed int);到了 C99,_Bool 也被支持了。

但编译器在具体实现时都进行了扩展,额外支持了 char、signed char、unsigned char 以及 enum 类型,所以上面的代码虽然不符合C语言标准,但它依然能够被编译器支持。

位域的存储

C语言标准并没有规定位域的具体存储方式,不同的编译器有不同的实现,但它们都尽量压缩存储空间。

位域的具体存储规则如下:

1) 当相邻成员的类型相同时,如果它们的位宽之和小于类型的 sizeof 大小,那么后面的成员紧邻前一个成员存储,直到不能容纳为止;如果它们的位宽之和大于类型的 sizeof 大小,那么后面的成员将从新的存储单元开始,其偏移量为类型大小的整数倍。

以下面的位域 bs 为例:

#include<stdio.h>

intmain(){
struct bs{
unsigned m:6;
unsigned n:12;
unsigned p:4;
};
printf("%d\n",sizeof(struct bs));

return0;
}

运行结果:

4

m、n、p 的类型都是 unsigned int,sizeof 的结果为 4 个字节(Byte),也即 32 个位(Bit)。m、n、p 的位宽之和为 6+12+4 = 22,小于 32,所以它们会挨着存储,中间没有缝隙。

sizeof(struct bs) 的大小之所以为 4,而不是 3,是因为要将内存对齐到 4 个字节,以便提高存取效率。

如果将成员 m 的位宽改为 22,那么输出结果将会是 8,因为 22+12 = 34,大于 32,n 会从新的位置开始存储,相对 m 的偏移量是 sizeof(unsigned int),也即 4 个字节。

如果再将成员 p 的位宽也改为 22,那么输出结果将会是 12,三个成员都不会挨着存储。

2) 当相邻成员的类型不同时,不同的编译器有不同的实现方案,GCC 会压缩存储,而 VC/VS 不会。

请看下面的位域 bs:

#include<stdio.h>

intmain(){
struct bs{
unsigned m:12;
unsignedchar ch:4;
unsigned p:4;
};
printf("%d\n",sizeof(struct bs));

return0;
}

在 GCC 下的运行结果为 4,三个成员挨着存储;在 VC/VS 下的运行结果为 12,三个成员按照各自的类型存储(与不指定位宽时的存储方式相同)。

m 、ch、p 的长度分别是 4、1、4 个字节,共计占用 9 个字节内存。

3) 如果成员之间穿插着非位域成员,那么不会进行压缩。例如对于下面的 bs:

struct bs{
unsigned m:12;
unsigned ch;
unsigned p:4;
};

在各个编译器下 sizeof 的结果都是 12。

通过上面的分析,我们发现位域成员往往不占用完整的字节,有时候也不处于字节的开头位置,因此使用&获取位域成员的地址是没有意义的,C语言也禁止这样做。地址是字节(Byte)的编号,而不是位(Bit)的编号。

无名位域

位域成员可以没有名称,只给出数据类型和位宽,如下所示:

struct bs{
int m:12;
int:20;//该位域成员不能使用
int n:4;
};

无名位域一般用来作填充或者调整成员位置。因为没有名称,无名位域不能使用。

上面的例子中,如果没有位宽为 20 的无名成员,m、n 将会挨着存储,sizeof(struct bs) 的结果为 4;有了这 20 位作为填充,m、n 将分开存储,sizeof(struct bs) 的结果为 8。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/331699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在CANoeCANalyzer中“在线回放”CAN Log.asc/blf文件

案例背景&#xff08;共11页精讲&#xff09;&#xff1a; 该篇博文将告诉您&#xff0c;在CANoe/CANalyzer中&#xff0c;“Online在线”模式下&#xff0c;回放一个CAN Log.asc/blf文件&#xff0c;重现那时CAN网络中CAM Message/报文的收发过程&#xff0c;让ECU在该环境下…

面试题:Redis常用数据结构

1 string基本编码方式&#xff0c;基于简单动态字符串(SDS)实现&#xff0c;存储上线为512mb.如果存储的SDS长度小于44字节&#xff0c;则会采用EMBSTR编码&#xff0c;此时object head与SDS是一段连续空间。申请内存时只需要调用一次内存分配函数&#xff0c;效率更高。如果存…

【官方 | 计算机二级Python教程】第九章:Python标准库概览

【官方 | 计算机二级Python教程】第九章&#xff1a;Python标准库概览参考书目第九章&#xff1a;Python标准库概览本章知识导图10.1 turtle库10.2 random库10.3 time库习题本文代码编译环境及版本更新日志参考书目 拜读的是计算机等级考试官方推荐教程 《全国计算机等级考试二…

JavaScript入门

介绍:JavaScript(通常缩写为JS)是一门基于原型和头等函数的多范式高级解释型编程语言, 它支持面向对象程序设计、指令式编程和函数式编程。它提供方法来操控文本、数组、日期和正则表达式等。不支持I/O, 比如网络、存储和图形等, 但这些都可以由它的宿主环境提供支持。目前它被…

以太网知识-GMII / RGMII接口

今天和海翎光电的小编一起分析MII/RMII/SMII&#xff0c;以及GMII/RGMII/SGMII接口的信号定义&#xff0c;及相关知识&#xff0c;同时小编也对RJ-45接口进行了总结&#xff0c;分析了在10/100模式下和1000M模式下的连接方法。GMII 接口分析GMII接口提供了8位数据通道&#xff…

“青春树儿童摄影网”首页制作

“青春树儿童摄影网”首页制作一、实验名称&#xff1a;二、实验日期&#xff1a;三、实验目的&#xff1a;四、实验内容&#xff1a;五、实验步骤&#xff1a;六、实验结果&#xff1a;七、源程序&#xff1a;八、心得体会&#xff1a;一、实验名称&#xff1a; “青春树儿童…

Nginx转发http到https和开机自动启动

场景&#xff1a; 以下都是基于windows系统&#xff08;ip为虚构&#xff09; 1.ip:172.16.54.55需要访问172.16.54.57的接口服务&#xff0c;来查看机械臂的运行状况 2.存在网络隔离&#xff0c;172.16.54.55无法直接访问172.16.54.57 3.172.16.54.56与172.16.54.57是机械…

reac面试题

1.React有什么特点&#xff1f;&#xff08;react的主要功能有哪些&#xff1f;&#xff09; 它用于虚拟DOM&#xff0c;组件化设计模式&#xff0c;声明式代码&#xff0c;单向数据流&#xff0c;使用jsx描述信息等特点 2.什么是组件化设计模式 复用的代码可以抽成组件共同…

VS Code 1.75 发布!

欢迎使用 2023 年 1 月版的 Visual Studio Code。希望您喜欢此版本中的许多更新&#xff0c;其中一些主要亮点包括&#xff1a;配置文件、VS Marketplace 签名、辅助功能改进、更轻松地调整多视图大小、树视图搜索历史、新的 Git 命令等等。让我们一起看看吧&#xff01; 配置文…

真实还原项目案例

真实模拟项目案例&#xff1a; 核心和出口用ospf&#xff0c;出口ospf路由用 default-route-advertise always 解决默认路由。 其它的都是常规的就不说了&#xff0c;都在配置里看配置。 出口路由配置&#xff1a; [H3C]dis current-configuration version 7.1.064, Release 04…

中国大学mooc 机器人操作系统讲义以及部分笔记

这里写目录标题二进制与源码包1.7 安装RoboWare Studio新的连接配套代码 官方看了一下课程官方的讲义连接&#xff0c;似乎很多页面已经丢失&#xff1f;或者是未授权&#xff1f;二进制与源码包 https://sychaichangkun.gitbooks.io/ros-tutorial-icourse163/content/chapter…

Web3中文|太心急!谷歌匆忙上线自家“ChatGPT”导致市值蒸发逾千亿美元

谷歌想证明它可以在AI竞赛中与微软抗衡&#xff0c;创建一个新的人工智能搜索引擎&#xff0c;但一个错误回答最终导致母公司 Alphabet 的市场损失超过千亿美元。 低开低走的美股市场 周三&#xff0c;美股三大指数低开低走。道琼斯指数收盘下跌207.68点&#xff0c;跌幅0.61%…

设计模式之单例模式(C++)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 一、单例模式是什么&#xff1f; 单例模式是一种创建型的软件设计模式&#xff0c;在工程项目中非常常见。通过单例模式的设计&am…

具有大部分相似的项目之间的项目整合

1.将多个项目文件合并&#xff0c;如&#xff1a;c2文件夹和c3文件夹不同&#xff0c;其余文件都是可以一起用的 2. router/index.js (1) 声明 公用路由&#xff0c;如 const common [{// :xxxx 代表任意匹配&#xff08;输啥都可以匹配&#xff09;path: /:channel/login,c…

html 浏览器存储方式

浏览器有三种本地存储方式&#xff1a; 1、localstorage 2、sessionStorage 3、cookie 浏览器 F12 打开调试模式&#xff0c;可以看到&#xff1a; 点击对应域名&#xff0c;可以看到当前域名下存储的数据&#xff0c;是以key&#xff0c;value形式存储的。 三种方式的共同…

某程序员去华为面试,因为错了一道题而被淘汰

题目有一道数学的逻辑题&#xff0c;这种提一般智商测试或者公务员考试中经常见到&#xff0c;传说华为有道面试题是这样的&#xff0c;求出下划线的数字应该是多少&#xff1f;请准备好纸和笔&#xff0c;思考10分钟&#xff0c;看看你能否得出正确答案。1分钟后。。。2分钟后…

MySQl学习(从入门到精通11)

MySQl学习&#xff08;从入门到精通11&#xff09;第 14 章_视图1. 常见的数据库对象2. 视图概述2. 1 为什么使用视图&#xff1f;2. 2 视图的理解3. 创建视图3. 1 创建单表视图3. 2 创建多表联合视图3. 3 基于视图创建视图4. 查看视图5. 更新视图的数据5. 1 一般情况5. 2 不可…

餐饮企业数据可视化大屏(智慧餐饮)

随着信息技术的深入发展&#xff0c;数据大屏的适用场景日益广泛&#xff0c;集工作汇报、实时监控和预测分析等功能于一身。 数据可视化的本质是视觉对话&#xff0c;数据可视化将数据分析技术与图形技术结合&#xff0c;清晰有效地将分析结果信息进行解读和传达。 当前很多餐…

第八天字符串

344.反转字符串力扣题目链接(opens new window)编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。你可以假设数组中…

数据结构|绪论

&#x1f525;Go for it!&#x1f525; &#x1f4dd;个人主页&#xff1a;按键难防 &#x1f4eb; 如果文章知识点有错误的地方&#xff0c;请指正&#xff01;和大家一起学习&#xff0c;一起进步&#x1f440; &#x1f4d6;系列专栏&#xff1a;数据结构与算法 &#x1f52…