学懂C语言(二十五):深入理解 C语言结构体 位域 的概念
目录
一、位域的基本概念
二、位域的定义
三、位域的内存分配和大小计算
示例1:简单位域
示例2:跨越多个存储单元
注意事项
结构体对齐控制
总结
C语言中的位域(Bit-Field)是一种特殊的数据结构,允许在结构体中定义占用特定位数的成员,主要用于节省存储空间并简化对特定位数数据的操作。位域一般用于需要紧凑表示某些标志(flags)或状态的场景,如硬件寄存器的模拟、协议头的解析等。以下是对C语言位域知识点的详细讲解。
一、位域的基本概念
- 定义:位域是指把一个字节(或其他整数类型)中的二进制位划分为几个不同的区域,每个区域有不同的位数,并允许在程序中通过域名来访问这些区域。
- 目的:通过仅占用必要的位数来存储数据,从而节省存储空间。
二、位域的定义
位域的定义与结构体的定义类似,但每个成员后面会跟随一个冒号和该成员所占的位数。定义形式如下:
struct 位域结构名 { 类型说明符 位域名:位域长度; ...
};
- 类型说明符:指定了位域的类型,如
int、unsigned int、char等。需要注意的是,位域的类型必须是整数类型。 - 位域名:为位域指定的名称,用于在程序中引用该位域。
- 位域长度:指定了位域占用的位数,这个长度必须小于或等于指定类型的位宽度。
示例:
struct BitField {unsigned int flag : 1;unsigned int value : 3;unsigned int mode : 4;
};
在这个例子中:
flag占用 1 位。value占用 3 位。mode占用 4 位。
三、位域的内存分配和大小计算
位域的内存分配和大小计算可能会因编译器和平台的不同而有所差异,但一般遵循以下原则:
- 相邻位域字段类型相同:
- 如果相邻位域字段的类型相同,且其位宽之和小于或等于类型的
sizeof大小(注意这里是指类型的位数,而不是sizeof操作符返回的字节数),则后面的字段将紧邻前一个字段存储,直到不能容纳为止。 - 如果相邻位域字段的类型相同,但其位宽之和大于类型的
sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍(以字节为单位,但实际对齐到的是位)。
- 如果相邻位域字段的类型相同,且其位宽之和小于或等于类型的
- 相邻位域字段类型不同:
- 这种情况下,不同编译器的实现可能有所不同。一些编译器可能会将不同类型的位域字段存放在不同的字节中,以确保对齐和访问效率。
- 结构体的总大小:
- 结构体的总大小通常是其最宽基本类型成员大小的整数倍,以满足内存对齐的要求。这意味着即使所有位域成员的总位数远小于一个字节,结构体也可能占用多个字节的内存。
示例1:简单位域
#include <stdio.h>struct BitField {unsigned int flag : 1;unsigned int value : 3;unsigned int mode : 4;
};int main() {printf("Size of struct BitField: %lu bytes\n", sizeof(struct BitField));return 0;
}
在这个例子中:
flag占用 1 位。value占用 3 位。mode占用 4 位。
总共:1 + 3 + 4 = 8 位,即1字节。但是,由于unsigned int一般需要4字节对齐,编译器可能会将整个结构体对齐到4字节。
Size of struct BitField: 4 bytes
示例2:跨越多个存储单元
#include <stdio.h>struct BitField {unsigned int a : 1;unsigned int b : 15;unsigned int c : 17;
};int main() {printf("Size of struct BitField: %lu bytes\n", sizeof(struct BitField));return 0;
}
在这个例子中:
a占用 1 位。b占用 15 位。c占用 17 位。
总共:1 + 15 + 17 = 33 位。由于unsigned int一般是4字节(32位),所以需要两个unsigned int存储。
Size of struct BitField: 8 bytes
注意事项
- 内存对齐:编译器可能会为满足硬件对齐要求而进行填充,这会影响结构体的大小。
- 平台相关性:不同编译器和不同硬件平台可能会对位域的大小和对齐方式有不同的处理方式。
- 跨平台兼容性:由于上述差异,位域在不同平台上的兼容性可能存在问题,需要小心处理。
- 性能考虑:尽管位域可以节省内存,但在某些平台上,操作位域的性能可能会较低,因为这些操作可能需要额外的指令来处理位操作。
为了确保结构体的大小符合预期,可以使用#pragma pack或其他编译器指令来控制对齐方式,但这需要根据具体情况谨慎使用。
结构体对齐控制
使用#pragma pack可以控制结构体的对齐方式,以确保结构体大小符合预期。
#include <stdio.h>#pragma pack(push, 1)
struct PackedBitField {unsigned int flag : 1;unsigned int value : 3;unsigned int mode : 4;
};
#pragma pack(pop)int main() {printf("Size of struct PackedBitField: %lu bytes\n", sizeof(struct PackedBitField));return 0;
}
在这个例子中,我们使用#pragma pack(push, 1)来将结构体对齐到1字节。
Size of struct PackedBitField: 1 bytes
这样可以确保结构体大小为1字节,且没有额外的填充位。
总结
C语言的位域是一种强大的数据结构,可以帮助开发者在节省存储空间的同时,方便地操作特定位数的数据。然而,由于编译器和平台的差异,位域的内存分配和大小计算可能会变得复杂。因此,在使用位域时,需要仔细考虑这些因素,并确保代码的可移植性和健壮性。
相关文章:
学懂C语言(二十五):深入理解 C语言结构体 位域 的概念
目录 一、位域的基本概念 二、位域的定义 三、位域的内存分配和大小计算 示例1:简单位域 示例2:跨越多个存储单元 注意事项 结构体对齐控制 总结 C语言中的位域(Bit-Field)是一种特殊的数据结构,允许在结构体中…...
LLM推理优化——KV Cache篇(百倍提速)
LLM推理优化——KV Cache篇(百倍提速) 注意:KV Cache本质上是空间换时间的技术。与计算机组成原理中的cache不同,它不涉及访存优化。 不知道大家在用LLM的时候,有没有注意到一个问题:我们在输入我们的问题…...
Linux进程--system
...
[Office] Word 特殊字符
0 打开“特殊字符集” 依次选择:Insert -> Symbol -> More Symbol 1 带圈编号 字体Font选择Wingdings...
联想电脑怎么重装系统_联想电脑U盘重装win10详细图文教程
联想电脑怎么重装系统?在当今科技发展迅猛的时代,联想电脑已经成为了人们生活中不可或缺的一部分。然而,随着时间的推移,我们可能会遇到一些问题,例如系统崩溃或者需要更换操作系统。这时,使用U盘来重新安装…...
前端开发者必备:揭秘谷歌F12调试的隐藏技巧!
前言 使用断点(breakpoint)是调试 JavaScript 代码的一种非常有效的方式。通过在代码的关键位置设置断点,可以阻止页面的状态变化,从而方便地检查和修改页面的当前状态。 1. 使用 setTimeout 配合 debugger 和 console.log setTi…...
vivado IP_REPO_PATHS
此属性允许您创建自定义IP目录,以与Vivado Design Suite一起使用。 IP_REPO_PATHS属性定义了一个或多个目录的路径,这些目录包含 第三方或用户定义的IP。指定的目录和任何子目录是 搜索要添加到Vivado Design Suite IP目录以用于设计的IP定义 进入或与IP…...
前端代码混淆加密(使用Terser、WebpackObfuscator)
零、相关技术及版本号 "vue": "2.6.12", "vue/cli-service": "4.4.6", "javascript-obfuscator": "^4.1.1", "terser-webpack-plugin": "^4.2.3", "vue-template-compiler": &quo…...
【复读EffectiveC++24】条款24:若所有参数皆需类型转换,请为此采用non-member函数
条款24:若所有参数皆需类型转换,请为此采用non-member函数 一、问题引入 举个例子,如果你设计一个表示有理数的类,允许从整型到有理数的隐式转换应该是合理的。在C内置类型中,从int转换到double也是再合理不过的了&a…...
Mac应用快速启动器:Alfred 5 for Mac 激活版
Alfred 5 是一款专为 macOS 系统设计的效率提升工具。这款软件以其快速启动和高效操作功能著称,通过使用快捷键来呼出输入界面,用户可以快速完成各种任务。 最新版本 Alfred 5.5 引入了一些新功能。其中包括整合了 ChatGPT 和 DALL-E,这意味…...
oracle语法介绍
Oracle数据库是关系型数据库管理系统之一,其SQL语法遵循标准的SQL规范,但也有一些自己的扩展。以下是一些Oracle SQL语法的基本示例: 1.选择数据: SELECT * FROM my_table; 1.插入数据: INSERT INTO my_table (colum…...
Python IDLE修改JetBrains Mono字体教程
自己在使用Python IDLE过程中发现原生字体不好看,不美观。尤其是对于部分字符,l打印不美观,区别不明显。于是诞生了换字体的想法。 教程简单,快速,3-5分钟不到即可完成。 目录 选型 下载安装 使用 选型 考虑到代码…...
CCF编程能力等级认证GESP—C++1级—20240629
CCF编程能力等级认证GESP—C1级—20240629 单选题(每题 2 分,共 30 分)判断题(每题 2 分,共 20 分)编程题 (每题 25 分,共 50 分)休息时间立方数 单选题(每题 2 分,共 30…...
继HBM之后, 内存领域新宠MCR DIMM闪亮登场!
随着人工智能(AI)和大数据的迅速发展,新型DRAM正迎来新的发展机遇。在服务器需求的推动下,MCRDIMM作为内存行业的新宠儿,正逐步登上历史舞台。 扩展阅读:MCR DIMM如何解决内存带宽瓶颈? MCR DIM…...
谷粒商城实战笔记-75-商品服务-API-品牌管理-品牌分类关联与级联更新
文章目录 一,引入Mybatis Plus分页插件二,品牌列表的模糊查询三,增加品牌测试数据四,开发后台品牌关联分类接口1,接口product/categorybrandrelation/catelog/list2,接口product/categorybrandrelation/sav…...
Java中的equals()与==的区别与用法
1. 区别 “”操作符用于比较两个对象的地址是否相等。.equals() 方法用于比较两个对象的内容是否相等。 Object 类的 .equals() 方法默认采用的是“”操作符进行比较。假如子类没有重写该方法的话,那么“”操作符和 .equals() 方法的功效就完全一样——比较两个对…...
【ai】 2005年 rule based expert system学习笔记1
PPT 是2005年的? Negnevitsky, Pearson Education 使用两种推理引擎的选择 backward chaining(逆向链接)推理过程 backward chaining(逆向链接)推理过程的GPT解释 这幅图展示了一个基于规则的专家系统如何通过backward chaining(逆向链接)推理过程来达到最终的推理目标…...
AI写作|去除了AI味道,我还花2分钟动手制作了一个coze智能体
本文背景: AI写出来的东西,机器味太浓? AI生成的文章内容质量不稳定、因为依赖于已有的数据和模式,AI可能很难创作出具有深度见解或独创性的内容 AI还无法完全理解复杂的上下文关系,导致生成的内容与用户期望的上下文不…...
数据集相关类代码回顾理解 | utils.make_grid\list comprehension\np.transpose
目录 utils.make_grid list comprehension np.transpose utils.make_grid x_gridutils.make_grid(x_grid, nrow4, padding2) make_grid 函数来自torchvision的utils模块,用于图像数据可视化,将一批图像排列成一个网格。 x_grid:四维图像…...
React前端面试每日一试 3.状态(State)和属性(Props)的区别是什么?
加粗样式先简单介绍一下Props和State的特点 Props(属性) Props(Properties)是React组件间传递数据的一种方式。它们是从父组件传递给子组件的只读数据,子组件不能修改这些数据。Props主要用于配置组件,使…...
嵌入式开发中的寄存器操作与函数指针应用
1. 嵌入式开发中的寄存器操作技巧在嵌入式系统开发中,直接操作硬件寄存器是最基础也是最核心的技能之一。寄存器是CPU与外围设备交互的窗口,通过读写特定内存地址的寄存器,我们可以控制硬件的行为。下面我将详细介绍几种常见的寄存器操作方法…...
高效大麦抢票自动化工具实战指南:开源项目的专业配置教程
高效大麦抢票自动化工具实战指南:开源项目的专业配置教程 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 大麦网作为国内领先的演出票务…...
数字IC时序约束实战:深入解析clock_uncertainty的设置策略与后端影响
1. 时钟不确定度的本质与组成 刚入行数字IC设计时,我最头疼的就是时序约束里那些看似相似却又微妙差别的概念。记得第一次看到clock_uncertainty这个参数,我盯着综合报告里的红色违例发了半小时呆。后来才明白,这个参数就像给时钟信号加了&qu…...
Neosegment库:面向七段数码管式NeoPixel的嵌入式驱动框架
1. Neosegment库概述:面向七段数码管式NeoPixel模块的嵌入式驱动框架Neosegment是一个专为Neosegment Digit模块设计的Arduino兼容嵌入式驱动库,其核心目标是将WS281x/SK6812系列智能LED的底层时序控制与七段数码管(7-segment display&#x…...
别再被@JsonFormat和@DateTimeFormat搞晕了!SpringBoot中时间处理的完整避坑指南
SpringBoot时间格式化终极指南:从JsonFormat到实战避坑 凌晨三点的办公室,咖啡杯已经见底,屏幕上却再次弹出那个熟悉的400错误——"Failed to parse Date value"。这可能是每个Java开发者在处理时间格式时都经历过的噩梦。时间数据…...
DS1881对数型数字电位器I²C驱动详解
1. DS1881 数字电位器驱动深度解析:面向嵌入式系统的IC对数型精密控制方案1.1 器件本质与工程定位DS1881 是 Dallas Semiconductor(后被 Maxim Integrated 收购)推出的单通道 IC 接口对数型数字电位器,其核心价值不在于“可编程电…...
Krita 5.3.0 与 6.0.0 发布:功能升级与技术革新
文本与工具革新,Krita 功能升级Krita 5.3.0 和 6.0.0 正式推出,带来了一系列显著的功能改进。文本工具被完全重写,支持在画布上进行所见即所得编辑,还能支持 OpenType 的所有特性以及文本置入形状,这大大提升了文字处理…...
2.2.2.3 Spark实战:词频统计
本次实战涵盖了Spark词频统计(WordCount)的两种主流实现方式。首先,利用Scala在spark-shell中完成从读取文件、flatMap分词、map映射到reduceByKey聚合的完整流程,并实现结果的降序排序。其次,针对Spark 3.3.2版本的需…...
S2-Pro模型部署在CentOS7生产环境:系统调优与安全加固
S2-Pro模型部署在CentOS7生产环境:系统调优与安全加固 1. 引言 在AI模型生产环境部署中,系统调优和安全加固往往是被忽视却至关重要的环节。很多团队花费大量精力优化模型性能,却因为基础环境配置不当导致服务不稳定或安全漏洞。本文将手把…...
前端开发者的福音:5分钟用Mergely.js给你的网页加个在线文本对比器
零成本打造专业级文本对比工具:Mergely.js全攻略 在代码审查、合同修订或是配置管理场景中,文本差异对比是个高频刚需。传统方案要么需要后端支持,要么功能简陋。现在,只需5分钟和几行JavaScript代码,你就能为Web项目嵌…...
