当前位置: 首页 > ai >正文

【207】VS2022 C++对unsigned char某一位(bit)的数据进行读写

在一些和硬件相关的场景下,为了节约设备空间,会给一个字节长度的变量中不同的位赋予不同的涵义。比如西门子 PLC 中布尔型变量就是占据一个字节(byte)中的一位(bit)。因此本文讨论了如何对字节中的某一位进行读写。

一、预备

01 与运算:两个数字都是 1 的时候,结果是 1 ;其他情况结果都是 0;也就是说 0 和任何数字做与运算结果都是 0

01 或运算:两个数字都是 0 的时候,结果是 0 ;其他情况结果都是 1;也就是说 1 和任何数字做或运算结果都是 1

二、读取

一个字节共 8 位,从低到高在代码中命名为第 0 位到 第 7 位。

当读取第零位数据的时候,把原数据和 1 做按位与,比如原数据 4 和 1 做按位与,如下:

00000100    # 4
00000001    # 1
--------
00000000    # 和 1 按位与,只有第 0 位是原始值,其他位因为和 0 按位与,都变 0

显然 4 的第 0 位是 0,和 1 按位与后还是 0。1 的第一到第七位都是 0,和 4 按位与后结果都是0。
如果换成 5 ,那么就是第 0 位是1,按位与后结果是 1。

当读取第一位数据的时候,把原数据和二进制数字 00000010 做按位与,也就是和 2 做按位与。结果要么是 0,要么是 2。这里可以利用 C++ if 语句对非 0 整数判真,对 0 判假的特性来写 C++ 代码。

以此类推,想要读取第 x 位的数据,就找一个第 x 位是 1、其他位是 0 的二进制数字来跟原数据做按位与,然后用 if 语句判断是不是 0 即可。由于二进制数字的数学特性,从第 0 位到第 7 位对应的数字分别是:

在这里插入图片描述

也就是说,根据要读取的位置不同,原数据要和对应的 1、2、4、8、16、32、64、128 做按位与。读者可以看一下后面代码中的 int readBit(unsigned char c, int bitPosition) 函数。

三、写入

一个字节共 8 位,从低到高在代码中命名为第 0 到 第 7 位。根据需求把字节中的某一位设置成 1 或 0。
我们要分两种情况讨论,分别是写入 1 和写入 0

3.1 写入 1

当向第零位写入 1 的时候,把原数据和 1 做按位或运算,比如原数据 4 和 1 做按位或,如下:

00000100    # 4
00000001    # 1
--------
00000101    # 和 1 按位或,只有第 0 位变成 1,其他位因为是按位或,值不变。

显然 4 的第 0 位是 0,和 1 做或运算变成 1,1 的第一到第七位都是 0 ,和 4 做按位或后值不变。结果是 5。

当向第一位写入 1 的时候,就需要让原数据和二进制数字 00000010 做按位或,也就是和 2 做按位或。

以此类推,想把第 x 位的数据置为 1,就把原数据和第 x 位是一、其他位是零的二进制数字做按位或,由于二进制数字的数学特性,从第 0 位到第 7 位对应的数字分别是:

在这里插入图片描述
即根据要写入 1 的位置不同,原数据要和对应的 1、2、4、8、16、32、64、128 做按位或运算。

3.2 写入 0

当向第 0 位写入 0 的时候,把原数据和 254 做按位与运算,比如原数据 5 和 1 做按位与,如下:

00000101  # 5
11111110  # 254
--------
00000100  # 和 254 按位与,只有第零位变成 0,其余位都是不变的。

显然 5 的第零位是 1;254 只有第零位是 0,第一到第七位都是 1;做按位与的时候只有 5 的第零位变成 0,其余位保持不变。结果是 4

当向第 1 位写入 0 的时候,需要让原数据和二进制数字 11111101 (即 253) 做按位与。

以此类推,要把第 x 位设置成 0,需要让原数据和一个第 x 位是0、其他位是 1 的二进制数字做按位与运算。由于二进制数字的数学特性,从第 0 位到第 7 位对应的数字分别是:

在这里插入图片描述

即根据要写入 0 的位置不同,原数据要和对应的 254、253、251、247、239、223、191、127 做按位与运算。

本文的代码中,int writeBit(unsigned char inCh, int bitPosition, bool data, unsigned char* outCh) 函数就是负责处理写入的。

四、代码

下面是 C++ 代码实现,在 VS 2022 上调试通过:

#include <stdio.h>
#include <stdlib.h>#include <random>// 从一个字节(byte)的数据中,读取某一位(bit)的数据。
// 一个字节的数据是8位的二进制数据,从低到高是 0 到 7 位,正常情况是返回 0 或 1.
// 如果有错误返回 -1
// unsigned char c 原数据
// int bitPosition 位置,范围从 0 到 7.
int readBit(unsigned char c, int bitPosition) {if (bitPosition < 0 || bitPosition > 7) {return -1;}unsigned char c2 = 0;switch (bitPosition) {case 0:c2 = c & 1;break;case 1:c2 = c & 2;break;case 2:c2 = c & 4;break;case 3:c2 = c & 8;break;case 4:c2 = c & 16;break;case 5:c2 = c & 32;break;case 6:c2 = c & 64;break;case 7:c2 = c & 128;break;}if (c2) {return 1;}else {return 0;}
}// 设置一个字节中某一位为0或1
// unsigned char inCh 输入参数,原来的单字节数据
// int bitPosition 字节中的位置,从低到高,数字是 0 到 7,(含 0 和 7 )
// bool data 要设置的数据,true 是 1,false 是 0。
// unsigned char* outCh 输出参数,inCh 变更后的结果。
// 返回0表示正常,返回-1表示出错。
int writeBit(unsigned char inCh, int bitPosition, bool data, unsigned char* outCh) {if (bitPosition < 0 || bitPosition > 7) {return -1;}unsigned char result = 0;if (data) {switch (bitPosition) {case 0:result = inCh | 1;break;case 1:result = inCh | 2;break;case 2:result = inCh | 4;break;case 3:result = inCh | 8;break;case 4:result = inCh | 16;break;case 5:result = inCh | 32;break;case 6:result = inCh | 64;break;case 7:result = inCh | 128;break;}}else {switch (data) {case 0:result = inCh & 254; // 255 - 1break;case 1:result = inCh & 253; // 255 - 2break;case 2:result = inCh & 251; // 255 - 4break;case 3:result = inCh & 247; // 255 - 8break;case 4:result = inCh & 239; // 255 - 16break;case 5:result = inCh & 223; // 255 - 32break;case 6:result = inCh & 191; // 255 - 64break;case 7:result = inCh & 127; // 255 - 128break;}}(*outCh) = result;return 0;
}// 生成 0 到 255 的随机数,包含0和255
unsigned char genRandom() {// 使用随机设备作为种子std::random_device rd;// 使用 Mersenne Twister 引擎std::mt19937 gen(rd());// 定义分布范围 [0, 255]std::uniform_int_distribution<> distr(0, 255);// 生成并输出随机数int result = distr(gen);return (unsigned char)result;
}int main(int argc, char** argv) {system("color 02");printf("argc=%d\n", argc);int ret = -1;// 生成随机数unsigned char n = genRandom();printf("n=%d\n", n);printf("readBit:\n");// 读取随机数的每一位数据,并以01的形式展现出来。for (int i = 7; i >= 0; i--) {ret = readBit(n, i);if (ret > -1) {printf("%d", ret);}else {printf("readBit Error !\n");}}printf("\n\n");unsigned char result;ret = writeBit(n, 0, false, &result);printf("writeBit:\n");if (0 != ret) {printf("writeBit Error! \n");}else {printf("%d\n", result);}return 0;
}
http://www.xdnf.cn/news/9547.html

相关文章:

  • dify本地部署的怎么更新新版本
  • matlab实现图像压缩编码
  • 4.8.3 利用SparkSQL统计每日新增用户
  • 微信小程序返回上一页监听
  • PG技术分享
  • 数据结构之队列实验
  • Nacos 服务注册发现案例:nacos-spring-cloud-example 详解
  • world quant教程学习二
  • 基于亚博K210开发板——物体分类测试
  • 【设计模式】责任链
  • PostgreSQL 内置扩展列表
  • HTML应用指南:利用GET请求获取全国罗森门店位置信息
  • 8000字回顾所有的HTML标签~
  • BSS / OSS 是什么
  • DBus总线详解
  • 华为OD机试真题——数字加减游戏(2025A卷:200分)Java/python/JavaScript/C/C++/GO最佳实现
  • uni-app 提供的页面跳转方法详细解释及其区别
  • 麒麟v10,arm64架构,编译安装Qt5.12.8
  • IEEE PRMVAI 2025 WS 26:计算机视觉前沿 Workshop 来袭!
  • 第十一章 管理Linux软件包和进程
  • 阅读笔记——理解什么是LLM大语言模型
  • 解决 NestJS 中热重载与实体类自动导入不能兼容的问题
  • 使用nvm use切换版本号,报exit status 5
  • spring4第3课-ioc控制反转-详解依赖注入的4种方式
  • 独立站引流新策略:AB站投放法助力突破瓶颈
  • JavaScript 中,require 和 import
  • zabbix6.x 监控mysql数据库
  • 【深度剖析】义齿定制行业数字化转型模式创新研究(上篇:行业概况)
  • Vulnhub_Zico2_wp
  • LNMP 架构部署