C++ 位运算 std::bitset类的使用介绍

news/2024/11/6 7:19:37/

简介

std::bitset<N> 是 C++ 标准库中的一个模板类,用于处理固定大小的位序列。这个类提供了一些方便的方法来操作位,例如设置、重置、翻转位等。

在这个上下文中,std::bitset<64> 创建了一个可以存储 64 位的位集。构造函数接受一个 unsigned long long 类型的参数,将其作为位集的初始值。这意味着,如果你有一个 uint64_t 类型的值(如声道布局的位掩码),你可以直接将其传递给 std::bitset<64> 的构造函数,它会将这个值的二进制表示形式作为位集的初始状态。

然后,你可以使用 bitsetoperator[] 来访问特定的位。例如,layout_bitset[i] 将返回位集中第 i 位的值。这个操作符返回一个 bitset::reference 类型的值,它可以自动转换为 bool,所以你可以直接在 if 语句中使用它。

总的来说,std::bitset 是一个非常方便的工具,可以让你更容易地处理位级别的操作。

相关接口

std::bitset 是一个非常有用的类,它提供了一系列的函数来操作和查询位集。以下是一些你可能会觉得有用的函数:

  1. bitset::size(): 返回位集中位的数量。

  2. bitset::count(): 返回位集中设置(即值为1)的位的数量。

  3. bitset::set(): 将位集中的所有位都设置为1。

  4. bitset::set(size_t pos, bool val = true): 将位集中指定位置的位设置为给定的值。

  5. bitset::reset(): 将位集中的所有位都重置为0。

  6. bitset::reset(size_t pos): 将位集中指定位置的位重置为0。

  7. bitset::flip(): 翻转位集中的所有位(即将所有的1变为0,将所有的0变为1)。

  8. bitset::flip(size_t pos): 翻转位集中指定位置的位。

  9. bitset::test(size_t pos): 检查位集中指定位置的位是否被设置。如果该位被设置,则返回 true;否则,返回 false

  10. bitset::operator[]: 通过下标访问位集中的位。例如,bitset[3] 会返回位集中第3位的值。

  11. bitset::to_string(): 将位集转换为字符串,其中每个字符代表一个位。

  12. bitset::to_ulong(), bitset::to_ullong(): 将位集转换为 unsigned longunsigned long long 类型的值。如果位集太大,无法转换为这些类型,那么这些函数会抛出 std::overflow_error 异常。

这些函数使得 std::bitset 成为处理位级别数据的强大工具。

std::bitset 的高级用法

std::bitset 是一个非常强大的工具,可以用于处理位级别的操作。除了基本的设置和获取位之外,它还提供了一些高级的功能。以下是一些 std::bitset 的高级用法:

  1. 位操作符std::bitset 支持位操作符 &|^~,以及相应的复合赋值操作符 &=|=^=。这些操作符可以用于执行位级别的 AND、OR、XOR 和 NOT 操作。

    std::bitset<4> b1("1100");
    std::bitset<4> b2("1010");
    std::bitset<4> b3 = b1 & b2; // bitwise AND
    std::bitset<4> b4 = b1 | b2; // bitwise OR
    std::bitset<4> b5 = b1 ^ b2; // bitwise XOR
    std::bitset<4> b6 = ~b1;     // bitwise NOT
    
  2. 位移操作符std::bitset 支持位移操作符 <<>>,以及相应的复合赋值操作符 <<=>>=。这些操作符可以用于执行位级别的左移和右移操作。

    std::bitset<4> b1("1100");
    std::bitset<4> b2 = b1 << 1; // left shift
    std::bitset<4> b3 = b1 >> 1; // right shift
    
  3. 比较操作符std::bitset 支持比较操作符 ==!=。这些操作符可以用于比较两个 bitset 是否相等。

    std::bitset<4> b1("1100");
    std::bitset<4> b2("1010");
    bool equal = (b1 == b2); // compare bitsets
    
  4. 其他有用的成员函数std::bitset 还提供了一些其他有用的成员函数,如 count()(返回设置的位数)、size()(返回位数)、test(size_t pos)(检查指定位置的位是否设置)、any()(检查是否有位设置)、none()(检查是否没有位设置)和 flip()(反转所有位)等。

    std::bitset<4> b1("1100");
    size_t count = b1.count(); // count set bits
    size_t size = b1.size();   // get number of bits
    bool bit = b1.test(2);     // test bit at position 2
    bool any = b1.any();       // check if any bit is set
    bool none = b1.none();     // check if no bit is set
    b1.flip();                 // flip all bits
    

以上就是 std::bitset 的一些高级用法。希望这些信息对你有所帮助!

底层实现

std::bitset 是一个模板类,它的构造函数有多种形式,可以接受不同类型的参数。以下是一些主要的构造函数:

  1. 默认构造函数:构造一个所有位都被设置为零的 bitset
  2. 从无符号长整型构造:初始化 bitset 的前 M 位(最右边,最低有效位)为 val 的对应位值,其中 M 是无符号长整型的位数和 bitset 的位数 N 中的较小者。如果 M 小于 N(bitset 比 32 位(直到 C++11)或 64 位(从 C++11 开始)长,对于典型的无符号长整型实现),剩余的位位置被初始化为零。
  3. 从字符串构造:使用 std::basic_string 中的字符构造 bitset。可以提供可选的起始位置 pos 和长度 n,以及表示设置(一)和未设置(零)位的替代字符。Traits::eq() 用于比较字符值。初始化字符串的有效长度是 min(n, str.size() - pos)。如果 pos > str.size(),此构造函数会抛出 std::out_of_range 异常。如果 str 中检查的任何字符都不是零或一,它会抛出 std::invalid_argument 异常。
  4. 类似于 (3),但使用 CharT* 而不是 std::basic_string。等价于 bitset(n == basic_string<CharT>::npos ? basic_string<CharT>(str) : basic_string<CharT>(str, n), 0, n, zero, one)

std::bitset 的底层实现依赖于编译器和平台,但基本的思想是使用一种紧凑的数据结构(通常是一个或多个无符号整数)来存储位。构造函数和其他成员函数则负责处理位的设置、清除和查询等操作。

以下是一个简单的示例,展示了如何使用不同的 std::bitset 构造函数:

#include <bitset>
#include <string>
#include <iostream>
#include <climits>int main()
{// empty constructorstd::bitset<8> b1; // [0,0,0,0,0,0,0,0]// unsigned long long constructorstd::bitset<8> b2(42);          // [0,0,1,0,1,0,1,0]std::bitset<70> bl(ULLONG_MAX); // [0,0,0,0,0,0,1,1,1,...,1,1,1] in C++11std::bitset<8> bs(0xfff0);      // [1,1,1,1,0,0,0,0]// string constructorstd::string bit_string = "110010";std::bitset<8> b3(bit_string);       // [0,0,1,1,0,0,1,0]std::bitset<8> b4(bit_string, 2);    // [0,0,0,0,0,0,1,0]std::bitset<8> b5(bit_string, 2, 3); // [0,0,0,0,0,0,0,1]// string constructor using custom zero/one digitsstd::string alpha_bit_string = "aBaaBBaB";std::bitset<8> b6(alpha_bit_string, 0, alpha_bit_string.size(),'a', 'B');         // [0,1,0,0,1,1,0,1]// char* constructor using custom digitsstd::bitset<8> b7("XXXXYYYY", 8, 'X', 'Y'); // [0,0,0,0,1,1,1,1]std::cout <<   "b1: " << b1 << "\nb2: " << b2 << "\nbl: " << bl<< "\nbs: " << bs << "\nb3: " << b3 << "\nb4: " << b4<< "\nb5: " << b5 << "\nb6: " << b6 << "\nb7: " << b7 << '\n';
}

这个示例创建了几个 std::bitset 对象,使用了不同的构造函数和参数。然后,它将每个 bitset 对象的内容打印到控制台。

使用场景

std::bitset 是一个非常有用的工具,它可以用于处理和操作位级别的数据。以下是一些 std::bitset 可能的使用场景:

  1. 位标志和开关:如果你有一组可以打开和关闭的标志,你可以使用 std::bitset 来存储它们。例如,你可能有一个配置对象,其中每个配置选项都可以打开或关闭。使用 std::bitset,你可以在一个紧凑的数据结构中存储所有这些选项的状态。

  2. 位掩码:位掩码是一种常见的编程技术,用于设置、清除和切换位。std::bitset 提供了一种方便的方式来处理位掩码。

  3. 二进制表示:如果你需要以二进制形式处理数据,std::bitset 是一个很好的工具。例如,你可能需要读取或写入二进制文件,或者你可能需要以二进制形式显示数据。

  4. 优化存储:如果你有一个大型数据集,其中每个元素只需要几位来存储,那么 std::bitset 可以帮助你节省空间。例如,如果你有一个包含几百万个元素的数组,每个元素都是一个小于 16 的整数,那么你可以使用 std::bitset 来存储这个数组,而不是使用一个整数数组。

  5. 加密和解密:在某些加密和解密算法中,需要对位进行操作。std::bitset 提供了一种方便的方式来处理这些操作。

  6. 网络编程:在网络编程中,数据通常以位的形式发送和接收。std::bitset 可以帮助处理这种位级别的数据。

  7. 硬件接口:在与硬件接口的编程中,通常需要对位进行操作,例如设置硬件寄存器的特定位。std::bitset 提供了一种方便的方式来处理这些操作。

总的来说,任何需要处理位级别数据的场景,std::bitset 都可能是一个有用的工具。

std::bitset 的线程完全性问题

std::bitset 是一个类模板,它提供了一种固定大小的位序列。它不提供任何内置的线程安全保证。这意味着,如果你在多个线程中同时访问或修改同一个 std::bitset 实例,你需要自己负责同步。

例如,如果你有一个 std::bitset,并且你在一个线程中设置位,同时在另一个线程中读取位,那么你可能会遇到数据竞争,这是一种未定义的行为。为了避免这种情况,你需要使用某种同步原语,如 std::mutex,来确保在任何时候只有一个线程可以访问 bitset

以下是一个简单的例子,展示了如何使用 std::mutex 来保护 std::bitset 的访问:

#include <bitset>
#include <thread>
#include <mutex>std::bitset<8> bits;
std::mutex mtx;void setBits()
{std::lock_guard<std::mutex> lock(mtx);bits.set();
}void printBits()
{std::lock_guard<std::mutex> lock(mtx);std::cout << bits << std::endl;
}int main()
{std::thread t1(setBits);std::thread t2(printBits);t1.join();t2.join();return 0;
}

在这个例子中,setBitsprintBits 函数都使用了 std::lock_guard 来锁定 mtx。这确保了在任何时候只有一个线程可以访问 bits。当 lock_guard 被销毁(即当它离开其作用域)时,它会自动释放锁,这使得锁的管理变得更加容易。

std::bitset 类的优缺点

std::bitset是C++标准库中的一个类,它可以存储和操作固定大小的位序列。

优点:

  1. 高效存储:位集可以有效地存储和处理大量的位,比其他容器类型使用更少的内存空间。

  2. 高效操作:位集提供了多种用于操作位的成员函数,如位反转、位计数等。

  3. 简化代码:使用位集可以简化与位操作相关的代码,提高代码的可读性和可维护性。

缺点:

  1. 固定大小:位集的大小在编译时确定,不能在运行时动态调整。如果需要处理动态大小的位序列,可能需要使用其他数据结构,如std::vector<bool>

  2. 功能限制:位集的功能相比于其他数据结构可能更为有限。例如,它没有提供排序或查找特定元素的直接方法。

  3. 与其他数据类型的互操作性:std::bitset不像标准容器那样可以与其他STL容器或数据类型进行流畅的互操作。


http://www.ppmy.cn/news/232295.html

相关文章

Linux :: 时间日历指令【3】:cal 指令:查询当日是今年的第几天、输出当前月历、指定月历、输出当前年历、指定年历

前言&#xff1a;本篇是 Linux 基本操作篇章的内容&#xff01; 笔者使用的环境是基于腾讯云服务器&#xff1a;CentOS 7.6 64bit。 学习集&#xff1a; C 入门到入土&#xff01;&#xff01;&#xff01;学习合集Linux 从命令到网络再到内核&#xff01;学习合集 目录索引&am…

显示屏漏光会有什么影响

液晶显示器漏光是常见问题&#xff0c;从某种意义上来说&#xff0c;液晶显示器基本上无法避免漏光的发生&#xff0c;只不过程度的问题。低档现实可能会比较明显&#xff0c;高档的就很少有明显的漏光。 漏光不会影响显示器本身的亮度、响应时间、寿命等基本技术参数。轻微漏光…

【js】判断文本是否溢出

需求&#xff1a;单行文本超出显示省略号&#xff0c;划过该文本时使用tooltip显示全部文本。 问题&#xff1a;由于数据是动态的&#xff0c;有时会很长&#xff0c;有时又比较短不会超出。如果一直保持显示tooltip就很不美观。 优化&#xff1a;超出文本时显示tooltip&…

js中内存泄漏与内存溢出

内存泄漏&#xff1a; 占用的内存没有及时的释放从而失去控制&#xff0c;从而造成内存的浪费。内存泄漏多了就容易引发内存溢出。 常见的造成内存泄漏的原因&#xff1a; &#xff08;1&#xff09;没有清除闭包 // 函数执行完后, 函数内的局部变量没有释放, 占…

AutoJS解锁手机屏幕

在脚本运行过程中经常碰到手机息屏导致脚本无法正常运行&#xff0c;这时就需要点亮屏幕&#xff0c;这次的教程主要就是教大家如何用AutoJS自动解锁手机。 以下是代码部分&#xff0c;这次的代码相对而言比较简单&#xff0c;判断手机是否处于息屏状态&#xff0c;如果是的话唤…

回收手机一般用什么软件测试,做二手手机回收的是用的什么检测软件?

检测软件只是用来检测您手机的配置、性能、运行等进行一个跑分的。 无闪现即加电开机后&#xff0c;能听到开机铃音、按键布景灯亮、闪现屏布景灯亮&#xff0c;但屏幕没有任何闪现内容&#xff1b;黑屏即加电开机后&#xff0c;能听到开机铃音、按键布景灯亮&#xff0c;但闪现…

安卓手机有坏点测试软件,检测手机屏幕是否有坏点的方法分享 怎么检测手机屏幕坏点...

如果发现手机屏幕有问题&#xff0c;比如坏点?那么手机屏幕坏点怎么检测?屏幕坏点检测既可以下载专门的坏点检测软件进行检测&#xff0c;也可以用最简单的方法使用纯色图片进行测试。如果你很认真&#xff0c;还可以使用放大镜之类的工具对结果进行验证。 方法/步骤 第一步&…