ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

C++位操作实战掩码、提取与组装

C++位操作实战掩码、提取与组装 在C编程中位操作是一项基础且强大的技术它允许程序员在二进制级别上直接操作数据。这种能力对于性能优化、内存节省以及底层硬件控制至关重要。本文将深入探讨C中的掩码操作、字节提取与组装并通过实例展示这些技术的实际应用。一、位运算符基础C中的基本位运算符按位与对两个数的每一位执行与操作仅当两个相应的位都为1时结果的该位才为1。按位或|对两个数的每一位执行或操作只要有一个相应的位为1结果的该位就为1。按位异或^对两个数的每一位执行异或操作当两个相应的位不同时结果的该位为1相同时为0。按位取反~对一个数的每一位执行取反操作0变为11变为0。左移将一个数的所有位向左移动指定的位数右边补0。左移相当于对数字进行2的n次幂的乘法运算n为移动的位数。右移将一个数的所有位向右移动指定的位数。对于无符号数高位补0对于有符号数处理方式因编译器而异可能补符号位算术右移或补0逻辑右移。示例1按位与清零、取指定位12345678910#include stdio.hintmain() {inttargetValue 0b11011010;// 二进制表示法intmask 0b00110011;intresult targetValue mask;// 应用掩码保留掩码中为1的位printf(原始: %08b\n, targetValue);printf(掩码: %08b\n, mask);printf(结果: %08b\n, result);return0;}输出原始: 11011010掩码: 00110011结果: 00011010示例2按位或保留指定位12345678910#include stdio.hintmain() {inta 0b00101011;intb 0b10010100;intresult a | b;// 按位或运算printf(a: %08b\n, a);printf(b: %08b\n, b);printf(结果: %08b\n, result);return0;}输出a: 00101011b: 10010100结果: 10111111示例3按位异或特定位翻转12345678910#include stdio.hintmain() {inta 0b01111010;intmask 0b00001111;intresult a ^ mask;// 按位异或运算翻转低4位printf(原始: %08b\n, a);printf(掩码: %08b\n, mask);printf(结果: %08b\n, result);return0;}输出原始: 01111010掩码: 00001111结果: 01110101示例4取反1234567891011#include stdio.hintmain() {inta 0b01111010;intresult ~a;// 取反运算printf(原始: %08b\n, a);printf(结果: %08b\n, result);return0;}输出原始: 01111010结果: 10000101示例5左移和右移12345678910#include stdio.hintmain() {inta 0b00001111;// 15的二进制表示intleftShiftResult a 2;// 左移2位intrightShiftResult a 2;// 右移2位逻辑移位printf(原始: %08b\n, a);printf(左移2位: %08b\n, leftShiftResult);// 相当于乘以4结果为60printf(右移2位: %08b\n, rightShiftResult);// 相当于除以4结果为3或-4取决于符号位和移位方式return0;}输出假设为逻辑移位原始: 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开始计数。我们可以使用以下代码12345678#include stdio.hintmain() {unsignedintnum 0;// 初始化为0unsignedintmask 1 5;// 创建一个掩码第5位为1其他位为0num | mask;// 使用或操作设置第5位printf(num: %u\n, num);// 输出结果应该看到第5位被设置为1return0;}示例2清除特定位现在假设我们想要清除num的第5位。我们可以使用以下代码12345678#include stdio.hintmain() {unsignedintnum 0x20;// 初始化为0x20二进制00100000第5位被设置unsignedintmask ~(1 5);// 创建一个掩码第5位为0其他位为1num mask;// 使用与操作清除第5位printf(num: %u\n, num);// 输出结果应该看到第5位被清除return0;}示例3检查特定位最后假设我们想要检查num的第5位是否被设置。我们可以使用以下代码123456789101112#include stdio.hintmain() {unsignedintnum 0x20;// 初始化为0x20二进制00100000第5位被设置unsignedintmask 1 5;// 创建一个掩码第5位为1其他位为0intbitIsSet (num mask) ! 0;// 使用与操作检查第5位是否被设置if(bitIsSet) {printf(The 5th bit is set.\n);}else{printf(The 5th bit is not set.\n);}return0;}三、字节提取与组装实战字节提取通过右移和掩码操作可以提取整数的特定字节。字节组装通过左移和按位或操作可以将多个字节组合成一个整数。字节提取示例假设我们有一个32位无符号整数num其值为0x12345678十六进制表示二进制为00010010 00110100 01010110 01111000。提取低8位最低字节12unsignedcharlowByte (unsignedchar)(num 0xFF);printf(Low byte: 0x%02X\n, lowByte);// 输出Low byte: 0x78这里0xFF是一个掩码其二进制表示为11111111。通过与操作我们保留了num的低8位并将其他位清零。然后我们将结果强制转换为unsigned char类型以确保它是一个字节大小。提取第二个字节从0开始计数12unsignedcharsecondByte (unsignedchar)((num 8) 0xFF);printf(Second byte: 0x%02X\n, secondByte);// 输出Second byte: 0x56首先我们通过右移操作 8将num的所有位向右移动8位这样原来的第二个字节就变成了新的低字节。然后我们再次使用0xFF掩码和与操作来提取这个新的低字节。字节组装示例现在假设我们有四个字节byte1 0x12byte2 0x34byte3 0x56byte4 0x78我们想要将它们组合成一个32位无符号整数。将两个字节组合成一个16位整数12unsignedcharsecondByte (unsignedchar)((num 8) 0xFF);printf(Second byte: 0x%02X\n, secondByte);// 输出Second byte: 0x56这里我们首先通过左移操作 8将byte1的所有位向左移动8位为byte2腾出空间。然后我们使用按位或操作|将byte1左移后的和byte2组合起来。将四个字节组合成一个32位整数12unsignedshortcombined16 (unsignedshort)((byte1 8) | byte2);printf(Combined 16-bit: 0x%04X\n, combined16);// 输出Combined 16-bit: 0x1234类似地我们分别将byte1、byte2、byte3向左移动24位、16位和8位然后将它们与byte4通过按位或操作组合起来。四、bitset 简介bitset是 C 标准库中一个非常有用的类模板它可以帮助我们高效地处理二进制数据。通过使用bitset我们可以方便地进行位设置、重置、翻转、检查、获取值以及位运算等操作。此外bitset还提供了遍历设置为 1 的位的功能使得处理二进制数据变得更加灵活和方便。引入头文件和定义bitset12#include bitsetstd::bitset8 myBitset;常用操作设置位使用set()函数可以将某个位设置为 1。例如1myBitset.set(3);// 将第 4 个位索引从 0 开始设置为 1重置位使用reset()函数可以将某个位设置为 0。如果调用时不带参数则会重置整个bitset。例如12myBitset.reset(3);// 将第 4 个位重置为 0myBitset.reset();// 重置整个 bitset翻转位使用flip()函数可以翻转某个位或者整个bitset的值。如果调用时不带参数则会翻转整个bitset。例如12myBitset.flip(3);// 翻转第 4 个位myBitset.flip();// 翻转整个 bitset检查位使用test()函数可以检查某个位是否为 1。例如1boolisBitSet myBitset.test(3);// 如果第 4 个位是 1则返回 true否则返回 false获取值使用to_string()函数可以获取bitset的字符串表示。例如1std::string bitsetString myBitset.to_string();// 返回一个表示 bitset 值的字符串位运算bitset还支持一些位运算操作如按位与、按位或、按位异或等。例如12std::bitset8 anotherBitset(10101010);myBitset anotherBitset;// 进行按位与操作遍历位使用find_first()和find_next()函数可以遍历设置为 1 的位。例如12345std::size_tpos myBitset.find_first();// 找到第一个设置为 1 的位的索引while(pos ! std::bitset8::npos) {// 处理设置为 1 的位pos myBitset.find_next(pos);// 找到下一个设置为 1 的位的索引}复制讲解五、其他位操作技术位旋转涉及将整数的位向左或向右循环移动。可以通过组合左移、右移和按位或操作来实现。位计数计算一个整数中设置为1的位的数量。可以使用逐位检查或使用更高效的算法如Brian Kernighan算法。位查找找到整数中第一个或最后一个设置为1的位的位置。可以使用逐位检查或使用内置函数如__builtin_ctz或__builtin_clz取决于编译器。位字段Bit-fields位字段是C和C中一种特殊的数据结构允许在结构体中定义位级别的成员。虽然位字段在节省内存空间方面非常有用但跨平台兼容性可能存在问题因为不同编译器对位字段的布局和填充有不同的处理方式。因此在使用位字段时需要谨慎并确保在目标平台上进行充分的测试。
返回列表