学懂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主要用于配置组件,使…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...
