C++位操作实战:掩码、提取与组装
在C++编程中,位操作是一项基础且强大的技术,它允许程序员在二进制级别上直接操作数据。这种能力对于性能优化、内存节省以及底层硬件控制至关重要。本文将深入探讨C++中的掩码操作、字节提取与组装,并通过实例展示这些技术的实际应用。
一、位运算符基础
C++中的基本位运算符:
- 按位与(&):对两个数的每一位执行与操作,仅当两个相应的位都为1时,结果的该位才为1。
- 按位或(|):对两个数的每一位执行或操作,只要有一个相应的位为1,结果的该位就为1。
- 按位异或(^):对两个数的每一位执行异或操作,当两个相应的位不同时,结果的该位为1,相同时为0。
- 按位取反(~):对一个数的每一位执行取反操作,0变为1,1变为0。
- 左移(<<):将一个数的所有位向左移动指定的位数,右边补0。左移相当于对数字进行2的n次幂的乘法运算(n为移动的位数)。
- 右移(>>):将一个数的所有位向右移动指定的位数。对于无符号数,高位补0;对于有符号数,处理方式因编译器而异,可能补符号位(算术右移)或补0(逻辑右移)。
示例1:按位与(清零、取指定位)
#include <stdio.h>int main() {int targetValue = 0b11011010; // 二进制表示法int mask = 0b00110011;int result = targetValue & mask; // 应用掩码,保留掩码中为1的位printf("原始: %08b\n", targetValue);printf("掩码: %08b\n", mask);printf("结果: %08b\n", result);return 0;
}
输出:
原始: 11011010
掩码: 00110011
结果: 00011010
示例2:按位或(保留指定位)
#include <stdio.h>int main() {int a = 0b00101011;int b = 0b10010100;int result = a | b; // 按位或运算printf("a: %08b\n", a);printf("b: %08b\n", b);printf("结果: %08b\n", result);return 0;
}
输出:
a: 00101011
b: 10010100
结果: 10111111
示例3:按位异或(特定位翻转)
#include <stdio.h>int main() {int a = 0b01111010;int mask = 0b00001111;int result = a ^ mask; // 按位异或运算,翻转低4位printf("原始: %08b\n", a);printf("掩码: %08b\n", mask);printf("结果: %08b\n", result);return 0;
}
输出:
原始: 01111010
掩码: 00001111
结果: 01110101
示例4:取反
#include <stdio.h>int main() {int a = 0b01111010;int result = ~a; // 取反运算printf("原始: %08b\n", a);printf("结果: %08b\n", result);return 0;
}
输出:
原始: 01111010
结果: 10000101
示例5:左移和右移
#include <stdio.h>int main() {int a = 0b00001111; // 15的二进制表示int leftShiftResult = a << 2; // 左移2位int rightShiftResult = a >> 2; // 右移2位(逻辑移位)printf("原始: %08b\n", a);printf("左移2位: %08b\n", leftShiftResult); // 相当于乘以4,结果为60printf("右移2位: %08b\n", rightShiftResult); // 相当于除以4,结果为3或-4(取决于符号位和移位方式)return 0;
}
输出(假设为逻辑移位):
原始: 00001111
左移2位: 00111100
右移2位: 00000011
二、掩码操作实战
掩码是一个二进制数,用于屏蔽不需要的位,只保留目标位。通过与操作(&),可以保留掩码中为1的位,其他位都被清零。在C/C++中使用掩码操作来设置、清除和检查整数的特定位。这些技术在性能优化、内存节省以及底层硬件控制中非常有用。
- 设置特定位:通过掩码与或操作,可以设置整数的特定位。例如,要设置32位整数的第5位(从0开始计数),可以使用
num | (1 << 5)。 - 清除特定位:通过掩码与取反操作,可以清除整数的特定位。例如,要清除32位整数的第5位,可以使用
num & ~(1 << 5)。 - 检查特定位:通过与操作,可以检查整数的特定位是否被设置。例如,要检查32位整数的第5位是否被设置,可以使用
(num & (1 << 5)) != 0。
示例1:设置特定位
假设我们有一个32位整数num,我们想要设置其中的第5位(从0开始计数)。我们可以使用以下代码:
#include <stdio.h> int main() { unsigned int num = 0; // 初始化为0 unsigned int mask = 1 << 5; // 创建一个掩码,第5位为1,其他位为0 num |= mask; // 使用或操作设置第5位 printf("num: %u\n", num); // 输出结果,应该看到第5位被设置为1 return 0;
}
示例2:清除特定位
现在,假设我们想要清除num的第5位。我们可以使用以下代码:
#include <stdio.h> int main() { unsigned int num = 0x20; // 初始化为0x20(二进制:00100000),第5位被设置 unsigned int mask = ~(1 << 5); // 创建一个掩码,第5位为0,其他位为1 num &= mask; // 使用与操作清除第5位 printf("num: %u\n", num); // 输出结果,应该看到第5位被清除 return 0;
}
示例3:检查特定位
最后,假设我们想要检查num的第5位是否被设置。我们可以使用以下代码:
#include <stdio.h> int main() { unsigned int num = 0x20; // 初始化为0x20(二进制:00100000),第5位被设置 unsigned int mask = 1 << 5; // 创建一个掩码,第5位为1,其他位为0 int bitIsSet = (num & mask) != 0; // 使用与操作检查第5位是否被设置 if (bitIsSet) { printf("The 5th bit is set.\n"); } else { printf("The 5th bit is not set.\n"); } return 0;
}
三、字节提取与组装实战
- 字节提取:通过右移和掩码操作,可以提取整数的特定字节。
- 字节组装:通过左移和按位或操作,可以将多个字节组合成一个整数。
字节提取示例
假设我们有一个32位无符号整数num,其值为0x12345678(十六进制表示,二进制为00010010 00110100 01010110 01111000)。
- 提取低8位(最低字节):
unsigned char lowByte = (unsigned char)(num & 0xFF);printf("Low byte: 0x%02X\n", lowByte); // 输出:Low byte: 0x78
这里,0xFF是一个掩码,其二进制表示为11111111。通过与操作&,我们保留了num的低8位,并将其他位清零。然后,我们将结果强制转换为unsigned char类型,以确保它是一个字节大小。
- 提取第二个字节(从0开始计数):
unsigned char secondByte = (unsigned char)((num >> 8) & 0xFF);printf("Second byte: 0x%02X\n", secondByte); // 输出:Second byte: 0x56
首先,我们通过右移操作>> 8将num的所有位向右移动8位,这样原来的第二个字节就变成了新的低字节。然后,我们再次使用0xFF掩码和与操作来提取这个新的低字节。
字节组装示例
现在,假设我们有四个字节byte1 = 0x12,byte2 = 0x34,byte3 = 0x56,byte4 = 0x78,我们想要将它们组合成一个32位无符号整数。
- 将两个字节组合成一个16位整数:
unsigned short combined16 = (unsigned short)((byte1 << 8) | byte2);printf("Combined 16-bit: 0x%04X\n", combined16); // 输出:Combined 16-bit: 0x1234
这里,我们首先通过左移操作<< 8将byte1的所有位向左移动8位,为byte2腾出空间。然后,我们使用按位或操作|将byte1(左移后的)和byte2组合起来。
- 将四个字节组合成一个32位整数:
unsigned int combined32 = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;printf("Combined 32-bit: 0x%08X\n", combined32); // 输出:Combined 32-bit: 0x12345678
类似地,我们分别将byte1、byte2、byte3向左移动24位、16位和8位,然后将它们与byte4通过按位或操作组合起来。
四、bitset 简介
bitset 是 C++ 标准库中一个非常有用的类模板,它可以帮助我们高效地处理二进制数据。通过使用 bitset,我们可以方便地进行位设置、重置、翻转、检查、获取值以及位运算等操作。此外,bitset 还提供了遍历设置为 1 的位的功能,使得处理二进制数据变得更加灵活和方便。
引入头文件和定义 bitset
#include <bitset>
std::bitset<8> myBitset;
常用操作
-
设置位:
使用
set()函数可以将某个位设置为 1。例如:myBitset.set(3); // 将第 4 个位(索引从 0 开始)设置为 1 -
重置位:
使用
reset()函数可以将某个位设置为 0。如果调用时不带参数,则会重置整个bitset。例如:myBitset.reset(3); // 将第 4 个位重置为 0 myBitset.reset(); // 重置整个 bitset -
翻转位:
使用
flip()函数可以翻转某个位或者整个bitset的值。如果调用时不带参数,则会翻转整个bitset。例如:myBitset.flip(3); // 翻转第 4 个位 myBitset.flip(); // 翻转整个 bitset -
检查位:
使用
test()函数可以检查某个位是否为 1。例如:bool isBitSet = myBitset.test(3); // 如果第 4 个位是 1,则返回 true,否则返回 false -
获取值:
使用
to_string()函数可以获取bitset的字符串表示。例如:std::string bitsetString = myBitset.to_string(); // 返回一个表示 bitset 值的字符串 -
位运算:
bitset还支持一些位运算操作,如按位与、按位或、按位异或等。例如:std::bitset<8> anotherBitset("10101010"); myBitset &= anotherBitset; // 进行按位与操作 -
遍历位:
使用
find_first()和find_next()函数可以遍历设置为 1 的位。例如:std::size_t pos = myBitset.find_first(); // 找到第一个设置为 1 的位的索引 while (pos != std::bitset<8>::npos) {// 处理设置为 1 的位pos = myBitset.find_next(pos); // 找到下一个设置为 1 的位的索引 }
五、其他位操作技术
- 位旋转:涉及将整数的位向左或向右循环移动。可以通过组合左移、右移和按位或操作来实现。
- 位计数:计算一个整数中设置为1的位的数量。可以使用逐位检查或使用更高效的算法(如Brian Kernighan算法)。
- 位查找:找到整数中第一个或最后一个设置为1的位的位置。可以使用逐位检查或使用内置函数(如
__builtin_ctz或__builtin_clz,取决于编译器)。 - 位字段(Bit-fields):位字段是C和C++中一种特殊的数据结构,允许在结构体中定义位级别的成员。虽然位字段在节省内存空间方面非常有用,但跨平台兼容性可能存在问题,因为不同编译器对位字段的布局和填充有不同的处理方式。因此,在使用位字段时需要谨慎,并确保在目标平台上进行充分的测试。
相关文章:
C++位操作实战:掩码、提取与组装
在C编程中,位操作是一项基础且强大的技术,它允许程序员在二进制级别上直接操作数据。这种能力对于性能优化、内存节省以及底层硬件控制至关重要。本文将深入探讨C中的掩码操作、字节提取与组装,并通过实例展示这些技术的实际应用。 一、位运算…...
PVE虚拟机强制重启
在Proxmox VE (PVE) 中,强制重启虚拟机的方法有几种,取决于具体场景和虚拟机的状态。以下是常用的两种方法: 1. 使用PVE Web UI强制重启虚拟机 如果虚拟机无法正常关闭或重启,可以使用PVE Web界面中的强制关机/重启选项…...
Adobe Acrobat DC 打印PDF文件,没有打印出注释的解决方法
adobe acrobat在打印的时候,打印不出来注释内容(之前一直可以,突然就不行),升级版本、嵌入字体等等都试过,也在Google找了半天和问了GPT也么找着办法。 无奈之下,自己通过印前检查,…...
主机名学习
1.主机名 定义:主机名是一个人类可读的标识符,通常由字母、数字和连接符组成,用于标识网络中的设备。主机名可以是局部的(例如局域网中的设备名)或者全局的(通过 DNS 解析成 IP 地址)。 解析&…...
SpringBoot循环依赖
在Spring Boot(以及Spring框架)中,循环依赖是指两个或多个Bean互相依赖,导致Spring在创建这些Bean时无法正常进行依赖注入。例如,假设有两个类A和B,A依赖于B,而B又依赖于A。在这种情况下&#x…...
一道面试题:为什么要使用Docker?
先来笼统地看一下 1、环境一致性 众所周知,开发过程中一个常见的问题是环境一致性问题,由于开发环境,测试环境,生产环境不一致,导致有些bug并未在开发过程中被发现,而Docker的镜像提供了除内核外完整的运…...
类的创建、构造器、实例属性、实例方法
Creating Classes # Class: blueprint for creating new Objects # Object: instance of a class # Class: Human # Objects: John, Mary, Jack# 类名定义每个单词的首字母大写 class Point:# 每个方法至少有一个参数def draw(self):print("draw")# 创建Point对象 p…...
js读取.txt文件内容
方法一:FileReader() <input type"file" id"fileInput" /><script>const fileInput document.getElementById(fileInput)fileInput.addEventListener(change, function (e) {const file e.target.files[0]const reader new Fil…...
【AscendC算子开发】笔记2 算子高级开发和调试调优
算子调试 Tensor也可以通过特定的printf方法来打印,见上图。 gdb调试见上图。 为什么gdb调试无法成功,因为run.sh里面有两行export,如果直接通过.XX运行的话需要配置一下。 npu域也支持调试,可以使用上述的方法。 内存检测工…...
vscode连接keil-5 开发STM32 程序
Vs Code连接 keil-5 ,开发STM32 程序 为了不使用难用的 keil-5 软件 继续使用友好的 vscode开发 步骤: 1 安装Keil Assitant 扩展 2 将你的 Keil-5 这个程序的路径找到复制到这里 3 下载 Mingw 下载点此处 4 下载后只解压 就行了 不安装 下载完 放在…...
数据结构深度优先搜索遍历连通图+非连通图(C语言代码+遍历+终端输入内容)
首先数据结构(C语言版第二版)的关于深度优先搜索遍历连通图的图G4如下: 使用邻接表去创建上面这个无向图,然后再使用书本DFS函数以及DFSTraverse函数实现深度优先搜索遍历 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #…...
信息安全工程师(55)网络安全漏洞概述
一、定义 网络安全漏洞,又称为脆弱性,是网络安全信息系统中与安全策略相冲突的缺陷,这种缺陷也称为安全隐患。漏洞可能导致机密性受损、完整性破坏、可用性降低、抗抵赖性缺失、可控性下降、真实性不保等问题。 二、分类 网络安全漏洞可以根据…...
member access within null pointer of type ‘ListNode‘
文章目录 前言一、空指针解引用二、访问已释放的内存三、 结构体定义问题四、错误的链表操作五、代码上下文六、示例代码七、调试建议 前言 p -> next p1; p1 p1 -> next; p p->next;runtime error: member access within null pointer of type ListNode如果出现…...
UE5蓝图中整理节点的方法
UE5蓝图中整理节点的方法 第一种:子图 右键选中的节点,出现一个面板,点击 Collapse Nodes 既可折叠选中的所有节点 注意:子图不可以被复制使用。 双击子图可以查看节点,若不想折叠选中的节点为子图,右键点…...
01,http 协议
1 ,http 协议 :介绍 1 ,http :是什么 Hyper Text Transfer Protocol :超文本传输协议 2 ,传输内容 :文本 1 ,内容 : 纯文本 2 ,特殊 …...
在 typescript 中,如何封装一个 class 类来接收接口的响应数据
在 TypeScript 中,封装一个类来接收接口的响应数据是一个常见的需求,特别是在处理后端 API 响应时。这通常涉及到定义与后端 API 响应结构相匹配的接口(或类型),并在类中创建方法来处理这些数据。以下是一个简单的示例…...
力扣周赛第420场 中等 3325.字符至少出现k次的子字符串 I
文章目录 题目介绍题解 题目介绍 题解 滑动窗口思想:参考 3.无重复字符的最长子串 链接 代码如下: class Solution {public int numberOfSubstrings(String s, int k) {int n s.length(), res 0;for(int left 0; left < n; left){// 记录窗口内…...
【Spring框架】Spring核心思想IoC以及依赖注入DI详解
目录 Spring框架前言 服务端三层开发表现层业务层持久层 Spring框架的概述Spring框架的优点Spring核心——IoC什么是IoC?O.o什么是耦合度? 创建第一个IoC程序导入必要依赖编写接口和实现类编写Spring核心配置文件测试类进行测试 Spring配置文件Bean对象的…...
Java项目-基于springboot框架的智慧外贸系统项目实战(附源码+文档)
作者:计算机学长阿伟 开发技术:SpringBoot、SSM、Vue、MySQL、ElementUI等,“文末源码”。 开发运行环境 开发语言:Java数据库:MySQL技术:SpringBoot、Vue、Mybaits Plus、ELementUI工具:IDEA/…...
Python程序控制结构 if语句详解
前面我们已经详细介绍了Python编程基础入门:从风格到数据类型再到表达式 在编程中,控制结构决定了代码的执行顺序。Python提供了丰富的控制结构,可以帮助程序根据不同条件做出不同的决策和操作。本文将深入介绍Python中常见的控制结构——包…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
