重生之我在异世界学编程之C语言:深入位段篇

大家好,这里是小编的博客频道
小编的博客:就爱学编程

很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!

本文目录

  • 引言
  • 正文
    • 一 位段的基本使用
      • (1)位段的声明
      • (2)位段的访问
    • 二 位段的大小计算
      • (1)从右向左分配位
      • (2)对齐要求
      • (3)填充位
    • 三 经典习题
      • 习题1:位段存储计算
      • 习题2:位段与对齐
      • 习题3:位段与结构体数组
      • 习题4:位段与位操作
      • 习题5:位段与内存映射
      • 习题6:位段与网络协议
      • 习题7:位段与嵌入式编程
      • 习题8:位段与数据压缩
      • 习题9:位段与错误检测
      • 习题10:位段与性能优化
    • 四 经典习题的详细解答
      • 习题1:位段存储计算
      • 习题2:位段与对齐
      • 习题3:位段与结构体数组
      • 习题4:位段与位操作
      • 习题5:位段与内存映射
      • 习题6:位段与网络协议
      • 习题7:位段与嵌入式编程
      • 习题8:位段与数据压缩
      • 习题9:位段与错误检测
      • 习题10:位段与性能优化
  • 快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

引言

在C语言中,结构体(struct)是一种复合数据类型,它允许我们将多个不同或相同类型的变量组合成一个单一的类型。除了基本的结构体使用外,C语言还提供了一种特殊的结构体成员——位段(bit fields),它允许程序员精确控制结构体成员的存储大小,通常用于打包数据以节省空间或匹配硬件接口。本文将详细介绍C语言中位段的使用、大小计算以及相关的经典习题。

在这里插入图片描述

正文


一 位段的基本使用

位段允许在结构体中定义占用特定位数的成员。这在需要精确控制数据存储格式时非常有用,尤其是在嵌入式编程中。

(1)位段的声明

位段的声明与普通结构体成员类似,只是在类型后面加上冒号(:)和位数

例:

struct BitField {
    unsigned int a : 1;  // 1位
    unsigned int b : 3;  // 3位
    unsigned int c : 4;  // 4位
    unsigned int d : 8;  // 8位
};

(2)位段的访问

位段成员的访问与普通结构体成员相同。

例:

struct BitField bf;
bf.a = 1;
bf.b = 7;
bf.c = 15;
bf.d = 255;

二 位段的大小计算

位段的大小计算涉及到几个关键点:对齐、填充和位段的总大小

(1)从右向左分配位

在C语言中,位段是从右向左分配的。这意味着第一个位段成员从结构体的最低有效位(最右边的位)开始,第二个成员紧随其后,依此类推。

(2)对齐要求

结构体的对齐要求通常由其成员中最大的对齐要求决定。例如,如果结构体中最大的成员是4字节的整数,那么整个结构体通常会按照4字节对齐。

(3)填充位

如果位段成员的总位数不是字节的倍数,编译器可能会在结构体的末尾添加填充位,以确保结构体的大小是字节的倍数。

计算示例

考虑以下结构体:

struct Example {
    unsigned int a : 1;
    unsigned int b : 2;
    unsigned int c : 5;
    unsigned int d : 8;
};

a占用1位。

b占用2位,与a相邻,共占用3位。

c占用5位,与b相邻,共占用8位,正好是一个字节。

d占用8位,与c相邻,共占用16位,正好是两个字节。

因此,这个结构体的大小是2字节,因为所有位段成员的总位数是16位,正好是2字节,不需要额外的填充位。


三 经典习题

习题1:位段存储计算

给定以下结构体:

struct Packed {
    unsigned int a : 1;
    unsigned int b : 2;
    unsigned int c : 4;
    unsigned int d : 8;
} __attribute__((packed));

计算该结构体的大小,并解释为什么。


习题2:位段与对齐

给定以下结构体:

struct Alignment {
    unsigned int a : 1;
    unsigned int b : 3;
    unsigned int c : 4;
};

计算该结构体的大小,并解释填充是如何工作的。


习题3:位段与结构体数组

给定以下结构体和数组:

structBitFields {
    unsigned int a : 1;
    unsigned int b : 3;
    unsigned int c : 4;
};
structBitFields array[10];

计算数组所占用的总内存,并解释为什么。


习题4:位段与位操作

给定以下结构体和函数:

structBitFields {
    unsigned int a : 1;
    unsigned int b : 3;
    unsigned int c : 4;
};

void setBitFields(structBitFields *bf, int a, int b, int c) {
    bf->a = a;
    bf->b = b;
    bf->c = c;
}

编写一个函数,该函数能够根据位段的值设置结构体的成员,并解释位操作是如何工作的。


习题5:位段与内存映射

考虑一个硬件设备,其寄存器映射如下:

struct DeviceRegisters {
    unsigned int status : 8;
    unsigned int control : 4;
    unsigned int mode : 2;
    unsigned int reserved : 18;
};


编写一个函数,该函数能够根据设备的状态和控制命令设置寄存器的值,并解释如何确保访问硬件寄存器时的内存对齐。


习题6:位段与网络协议

给定一个网络协议的数据包结构:

struct NetworkPacket {
    unsigned int header : 16;
    unsigned int type : 4;
    unsigned int length : 12;
};

编写一个函数,该函数能够解析网络数据包,并根据数据包的类型和长度处理数据包,并解释位段在网络协议中的应用。


习题7:位段与嵌入式编程

考虑一个嵌入式系统中的LED控制结构:

struct LEDControl {
    unsigned int led1 : 1;
    unsigned int led2 : 1;
    unsigned int led3 : 1;
    unsigned int led4 : 1;
    unsigned int led5 : 1;
    unsigned int led6 : 1;
    unsigned int led7 : 1;
    unsigned int led8 : 1;
};

编写一个函数,该函数能够根据LED的状态控制LED的亮灭,并解释位段在嵌入式编程中的应用。


习题8:位段与数据压缩

给定一个数据压缩算法,需要将以下结构体压缩:


struct CompressedData {
    unsigned int data1 : 6;
    unsigned int data2 : 10;
    unsigned int data3 : 10;
};

编写一个函数,该函数能够将结构体的数据压缩到一个字节中,并解释位段在数据压缩中的应用。


习题9:位段与错误检测

给定以下结构体,用于错误检测:

struct ErrorDetection {
    unsigned int data : 16;
    unsigned int parity : 8;
};

编写一个函数,该函数能够根据数据计算校验位,并解释位段在校验中的应用。


习题10:位段与性能优化

给定以下结构体,用于性能监控:

struct PerformanceMonitor {
    unsigned int counter1 : 8;
    unsigned int counter2 : 8;
    unsigned int counter3 : 8;
    unsigned int counter4 : 8;
};
















四 经典习题的详细解答

习题1:位段存储计算

分析:
__attribute__((packed))告诉编译器不要为结构体添加任何填充(padding),因此结构体的大小将正好等于其成员所占的位数总和。

答案:
结构体Packed的大小为 1(a)+2(b)+4(c)+8(d)=15位。由于1字节等于8位,所以这个结构体将占用2字节。


习题2:位段与对齐

分析:
在这个结构体中,a占用1位,b占用3位,c占用4位。由于ba一起占用了4位,它们可以放在同一个字节中。c需要一个新的字节,因为它不能和b放在同一个字节中(因为b已经占用了3位)。

答案:
结构体Alignment的大小为 1字节(包含ab)+1字节(c)=2字节。


习题3:位段与结构体数组

分析:
结构体BitFields的大小取决于其成员所占的位数总和。由于abc分别占用1位、3位和4位,它们可以放在同一个字节中。

答案:
结构体BitFields的大小为 1字节。因此,数组array[10]将占用 10 * 1字节=10字节。


习题4:位段与位操作

分析:
位操作通常用于设置、清除、翻转和测试位段的值。

答案:

void setBitFields(structBitFields *bf, int a, int b, int c) {
    bf->a = !!a; // 确保a是0或1
    bf->b = b & 0x7; // 确保b在0到7之间
    bf->c = c & 0xF; // 确保c在0到15之间
}

习题5:位段与内存映射

分析:
在访问硬件寄存器时,需要确保地址对齐,并且使用正确的位操作来设置值。

答案:

void setDeviceRegister(struct DeviceRegisters *regs, int status, int control, int mode) {
    regs->status = status & 0xFF; // 确保status在0到255之间
    regs->control = control & 0xF; // 确保control在0到15之间
    regs->mode = mode & 0x3; // 确保mode在0到3之间
}



习题6:位段与网络协议

分析:
解析网络数据包时,需要根据位段的值提取信息,并进行相应的处理。

答案:

void processNetworkPacket(struct NetworkPacket *packet) {
    // 根据packet->type处理数据包
    // 根据packet->length处理数据包内容
}


习题7:位段与嵌入式编程

分析:
在嵌入式编程中,位段常用于控制硬件设备,如LED。

答案:

void controlLED(struct LEDControl *leds, int led1, int led2, int led3, int led4, int led5, int led6, int led7, int led8) {
    leds->led1 = !!led1;
    leds->led2 = !!led2;
    // ... 对其他LED进行类似操作
}

习题8:位段与数据压缩

分析:
数据压缩通常涉及到将多个值编码到更少的位数中。

答案:

unsigned char compressData(struct CompressedData *data) {
    return (data->data1 << 6) | (data->data2 << 16 - 10) | data->data3;
}

习题9:位段与错误检测

分析:
校验位通常用于错误检测,如奇偶校验。

答案:

unsigned char calculateParity(struct ErrorDetection *errDetect) {
    unsigned char parity = 0;
    // 计算errDetect->data的奇偶校验位
    // 返回计算出的parity值
}

习题10:位段与性能优化

分析:
性能监控可能涉及到跟踪和记录事件的发生次数。

答案:

void monitorPerformance(struct PerformanceMonitor *perf) {
    // 根据perf->counter1到perf->counter4的值监控性能
}

以上是每个习题的分析及答案。每个习题的解释和代码示例都相对简洁。在实际应用中,可能需要更详细的错误处理和边界检查。希望这些示例能够帮助你理解位段在C语言中的应用。

结论:

  • 位段是C语言中一个强大的特性,它允许程序员精确控制数据的存储和访问。通过合理使用位段,可以有效地节省内存空间,提高程序的性能,尤其是在嵌入式系统和硬件接口编程中。掌握位段的使用和大小计算对于C语言程序员来说是一项重要的技能。

快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2. 读取文件

题目4: 读取excel 文件2_1People,查看数据结构(行与列数,列名),观察数据内容(前3行与后3行) import pandas as pd# 题目4: 读取excel 文件2_1People,查看数据结构(行与列数,列名),观察数据内容(前3行与后3行) people pd.read_excel(2_1People.xlsx) print(people.shape) #…

【Mac】安装Gradle

1、说明 Gradle 运行依赖 JVM&#xff0c;需要先安装JDK&#xff0c;Gradle 与 JDK的版本对应参见&#xff1a;Java Compatibility IDEA的版本也是有要求Gradle版本的&#xff0c;二者版本对应关系参见&#xff1a;Third-Party Software and Licenses 本次 Gradle 安装版本为…

【人工智能基础06】人工神经网络(练习题):神经网络的计算、激活函数的选择与神经网络的退化

文章目录 1. 基于神经网络计算心理健康程度2. 添加激活函数的神经网络计算3. 使用神经网络预测小胖是否会变胖4. 激活函数选择的讨论5. 神经网络的设计6. 深度线性模型的表达能力线性模型7. 神经网络退化 主要讨论的内容 什么是人工神经网络&#xff0c;相关计算反向传播算法的…

Lua语言入门 - Lua 数组

Lua 数组 数组&#xff0c;就是相同数据类型的元素按一定顺序排列的集合&#xff0c;可以是一维数组和多维数组。 在 Lua 中&#xff0c;数组不是一种特定的数据类型&#xff0c;而是一种用来存储一组值的数据结构。 实际上&#xff0c;Lua 中并没有专门的数组类型&#xff…

在Linux(ubuntu22.04)搭建rust开发环境

1.安装rust 1.安装curl: sudo apt install curl 2.安装rust最新版 curl --proto ‘https’ --tlsv1.2 https://sh.rustup.rs -sSf | sh 安装完成后出现&#xff1a;Rust is installed now. Great! 重启当前shell即可 3.检验是否安装成功 rustc --version 结果出现&…

链表OJ题型讲解与总结

目录 一.引言 二.链表题型详细讲解 一.移除链表元素 二.反转单链表 三.链表的中间结点 四.链表返回倒数第k个节点 五.合并两个有序链表 六.链表分割 七.链表的回文结构 三.总结与提升 一.引言 在我们学习完单链表与双链表后&#xff0c;真诚建议初学者能够掌握单双链表…

深入理解 Fork/Join 并行计算框架

在并发编程领域&#xff0c;任务模型可以分为简单并行任务、聚合任务和批量并行任务。然而&#xff0c;还有一种广泛应用的任务模型——分治&#xff08;Divide and Conquer&#xff09;。分治是一种解决复杂问题的思维方法&#xff0c;它通过将复杂问题分解为多个相似的子问题…

小尺寸低功耗蓝牙模块在光伏清扫机器人上的应用

一、引言 随着可再生能源的迅速发展&#xff0c;光伏发电系统的清洁与维护变得越来越重要。光伏清扫机器人通过自动化技术提高了清洁效率&#xff0c;而蓝牙模组的集成为这些设备提供了更为智能的管理和控制方案。 二、蓝牙模组的功能与实现&#xff1a; 蓝牙模组ANS-BT103M…

沁恒CH32V208蓝牙串口透传例程:修改透传的串口

从事嵌入式单片机的工作算是符合我个人兴趣爱好的,当面对一个新的芯片我即想把芯片尽快搞懂完成项目赚钱,也想着能够把自己遇到的坑和注意事项记录下来,即方便自己后面查阅也可以分享给大家,这是一种冲动,但是这个或许并不是原厂希望的,尽管这样有可能会牺牲一些时间也有哪天原…

【触想智能】工业安卓一体机日常维护注意事项以及其应用领域分析

工业安卓一体机是一种集成了安卓操作系统的工业控制设备。它广泛应用于各种工业场景&#xff0c;为生产和管理提供了便利。 为了保证工业安卓一体机的正常运行和延长其寿命&#xff0c;日常维护工作是十分重要的。下面是一些工业安卓一体机日常维护的注意事项&#xff0c;以及其…

12.6深度学习_模型优化和迁移_模型移植

八、模型移植 1. 认识ONNX ​ https://onnx.ai/ ​ Open Neural Network Exchange&#xff08;ONNX&#xff0c;开放神经网络交换&#xff09;格式&#xff0c;是一个用于表示深度学习模型的标准&#xff0c;可使模型在不同框架之间进行转移。 ​ ONNX的规范及代码主要由微软…

2-2-18-14 QNX系统架构之 TCP/IP 网络

阅读前言 本文以QNX系统官方的文档英文原版资料为参考&#xff0c;翻译和逐句校对后&#xff0c;对QNX操作系统的相关概念进行了深度整理&#xff0c;旨在帮助想要了解QNX的读者及开发者可以快速阅读&#xff0c;而不必查看晦涩难懂的英文原文&#xff0c;这些文章将会作为一个…

实战:MyBatis适配多种数据库:MySQL、Oracle、PostGresql等

概叙 很多时候&#xff0c;一套代码要适配多种数据库&#xff0c;主流的三种库&#xff1a;MySQL、Oracle、PostGresql&#xff0c;刚好mybatis支持这种扩展&#xff0c;如下图所示&#xff0c;在一个“namespace”&#xff0c;判断唯一的标志是iddatabaseId&#xff0c;刚好写…

电子信息工程自动化 单片机彩灯控制

摘要 随着社会经济和科学技术的不断进步&#xff0c;人们在保持发展的同时&#xff0c;环境带给人类的影响已经不足以让我们忽视&#xff0c;所以城市的美化问题慢慢的进入了人们的眼帘&#xff0c;PLC的产生给带电子产品带来了巨大变革&#xff0c;彩灯的使用在城市的美化中变…

【后台管理系统】-【组件封装】

目录 组件封装搜索组件table列表组件content组件自定义插槽定制modal组件动态获取options数据 组件封装 搜索组件 给页面写一个配置文件&#xff0c;将配置文件传入组件&#xff0c;可直接生成页面&#xff0c;以下面页面为例&#xff0c; 新建src/views/main/system/depart…

「嵌入式系统设计与实现」书评:学习一个STM32的案例

本文最早发表于电子发烧友论坛&#xff1a;【新提醒】【「嵌入式系统设计与实现」阅读体验】 学习一个STM32的案例 - 发烧友官方/活动 - 电子技术论坛 - 广受欢迎的专业电子论坛!https://bbs.elecfans.com/jishu_2467617_1_1.html 感谢电子发烧友论坛和电子工业出版社的赠书。 …

设计模式:20、状态模式(状态对象)

目录 0、定义 1、状态模式的三种角色 2、状态模式的UML类图 3、示例代码 0、定义 允许一个对象在其内部状态改变时改变它的行为&#xff0c;对象看起来似乎修改了它的类。 1、状态模式的三种角色 环境&#xff08;Context&#xff09;&#xff1a;环境是一个类&#xff0…

idea中新建一个空项目

目的&#xff0c;为了在同一个目录下有多个小的项目&#xff1a;使用IDE为idea2022。 步骤&#xff1a; 点击新建项目&#xff0c;点击创建空项目&#xff0c;这里选择空项目是将其作为其他项目的一个容器&#xff0c;如图所示&#xff1a; 然后点击文件->项目结构&#xf…

Java基础复习

“任何时候我也不会满足&#xff0c;越是多读书&#xff0c;就越是深刻地感到不满足&#xff0c;越感到自己知识贫乏。科学是奥妙无穷的。” ——马克思 目录 一、方法&方法重载 二、运算符 三、数据类型 四、面向对象 1. 面向对象思想 2. 引用传递 3. 访问权限修饰…

嵌入式里的“移植”概念

这里因为最近一年看到公司某项目很多代码上有直接硬件的操作&#xff0c;这里有感而发&#xff0c;介绍移植的概念。 一、硬件 先上一个图&#xff1a; 举个例子&#xff0c;大学里应该都买过开发板&#xff0c;例如st的&#xff0c;这里三个层次&#xff0c; 内核&#xff…