标准库标头 <bit>(C++20)学习

<bit>头文件是数值库的一部分。定义用于访问、操作和处理各个位和位序列的函数。例如,有函数可以旋转位、查找连续集或已清除位的数量、查看某个数是否为 2 的整数幂、查找表示数字的最小位数等。

|-----------------------------------------------------------------------------------------------------|--------------------------------|
| #### 类型 ||
| endian (C++20) | 指示标量类型的端序 (枚举) |
| #### 函数 ||
| bit_cast (C++20) | 将一个类型的对象表示重解释为另一类型的对象表示 (函数模板) |
| byteswap (C++23) | 反转给定整数值中的字节 (函数模板) |
| has_single_bit (C++20) | 检查一个数是否为 2 的整数次幂 (函数模板) |
| bit_ceil (C++20) | 寻找不小于给定值的最小的二的整数次幂 (函数模板) |
| bit_floor (C++20) | 寻找不大于给定值的最大的二的整数次幂 (函数模板) |
| bit_width (C++20) | 寻找表示给定值所需的最小位数 (函数模板) |
| rotl (C++20) | 计算逐位左旋转的结果 (函数模板) |
| rotr (C++20) | 计算逐位右旋转的结果 (函数模板) |
| countl_zero (C++20) | 从最高位起计量连续的 0 位的数量 (函数模板) |
| countl_one (C++20) | 从最高位起计量连续的 1 位的数量 (函数模板) |
| countr_zero (C++20) | 从最低位起计量连续的 0 位的数量 (函数模板) |
| countr_one (C++20) | 从最低位起计量连续的 1 位的数量 (函数模板) |
| popcount (C++20) | 计量无符号整数中为 1 的位的数量 (函数模板) |

下面来看一下它的具体使用示例:

endian判断CPU的大小端序

cpp 复制代码
#include <bit>
#include <iostream>

//检测处理器端序,返回值:0表大端序,1表示小端序
//小端序低位存放低地址,例如:16bit的数0x1234在小端序模式CPU内存中的存放方式(假设从地址0x2000开始存放)为
//0x2000     0x34
//0x2001     0x12
int checkCPUendian()
{
    union w
    {
        int a;
        char b;
    }c;
    c.a = 1;
    return (c.b == 1);
}


int main()
{
    if constexpr (std::endian::native == std::endian::big)
        std::cout << "大端\n";
    else if constexpr (std::endian::native == std::endian::little)
        std::cout << "小端\n";
    else
        std::cout << "混合端序\n";

    int ret = checkCPUendian();
    std::cout << "ret======" << ret << std::endl;
    if (ret)
        std::cout << "CPU为小端序\n";
    else
        std::cout << "CPU为大端序\n";
    
    return 0;
}

运行结果:

运行的时候要把编译器设置为C++20或最新的c++标准

函数示例:

cpp 复制代码
#include <bit>
#include <concepts>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <bitset>
#include <cmath>

template <std::integral T>
void dump(T v, char term = '\n')
{
    std::cout << std::hex << std::uppercase << std::setfill('0')
        << std::setw(sizeof(T) * 2) << v << " : ";
    for (std::size_t i{}; i != sizeof(T); ++i, v >>= 8)
        std::cout << std::setw(2) << static_cast<unsigned>(T(0xFF) & v) << ' ';
    std::cout << std::dec << term;
}

static_assert(std::popcount(0xFULL) == 4);

int main()
{
    //1.bit_cast example 将一个类型的对象表示重解释为另一类型的对象表示 
    float f = std::numeric_limits<float>::infinity();
    int i = std::bit_cast<int>(f);
    std::cout << "float f = " << std::hex << f
        << "\nstd::bit_cast<int>(f) = " << std::hex << i << '\n';
    
    //2.byteswap example反转给定整数值中的字节 
    static_assert(std::byteswap('a') == 'a');
    std::cout << "U16 的 byteswap:\n";
    constexpr auto x = std::uint16_t(0xCAFE);
    dump(x);
    dump(std::byteswap(x));

    std::cout << "\nU32 的 byteswap:\n";
    constexpr auto y = std::uint32_t(0xDEADBEEFu);
    dump(y);
    dump(std::byteswap(y));

    std::cout << "\nU64 的 byteswap:\n";
    constexpr auto z = std::uint64_t{ 0x0123456789ABCDEFull };
    dump(z);
    dump(std::byteswap(z));

    //3.has_single_bit example检查一个数是否为 2 的整数次幂
    for (auto u = 0u; u != 10; ++u)
    {
        std::cout << "u = " << u << " = " << std::bitset<4>(u);
        if (std::has_single_bit(u)) // P1956R1 前为 `ispow2`
            std::cout << " = 2^" << std::log2(u) << " (为二的幂)";
        std::cout << '\n';
    }

    //4.bit_ceil example寻找不小于给定值的最小的二的整数次幂
    using bin = std::bitset<8>;
    for (unsigned x{ 0 }; x != 10; ++x)
    {
        unsigned const z = std::bit_ceil(x); // P1956R1 前为 `ceil2`
        std::cout << "bit_ceil( " << bin(x) << " ) = " << bin(z) << '\n';
    }

    //5.bit_floor example寻找不大于给定值的最大的二的整数次幂
    using bin = std::bitset<8>;
    for (unsigned x = 0; x != 10; ++x)
    {
        auto const z = std::bit_floor(x); // P1956R1 前为 `floor2`
        std::cout << "bit_floor( " << bin(x) << " ) = " << bin(z) << '\n';
    }

    //6.bit_width example寻找表示给定值所需的最小位数
    for (unsigned x{ 0 }; x != 8; ++x)
    {
        std::cout << "bit_width( "
            << std::bitset<4>{x} << " ) = "
            << std::bit_width(x) << '\n';
    }

    //7.rotl example计算逐位左旋转的结果
    std::uint8_t i7 = 0b00011101;
    std::cout << "i7          = " << std::bitset<8>(i7) << '\n';
    std::cout << "rotl(i7,0)  = " << std::bitset<8>(std::rotl(i7, 0)) << '\n';
    std::cout << "rotl(i7,1)  = " << std::bitset<8>(std::rotl(i7, 1)) << '\n';
    std::cout << "rotl(i7,4)  = " << std::bitset<8>(std::rotl(i7, 4)) << '\n';
    std::cout << "rotl(i7,9)  = " << std::bitset<8>(std::rotl(i7, 9)) << '\n';
    std::cout << "rotl(i7,-1) = " << std::bitset<8>(std::rotl(i7, -1)) << '\n';

    //8.rotr example计算逐位右旋转的结果
    std::uint8_t i8 = 0b00011101;
    std::cout << "i8          = " << std::bitset<8>(i8) << '\n';
    std::cout << "rotr(i8,0)  = " << std::bitset<8>(std::rotr(i8, 0)) << '\n';
    std::cout << "rotr(i8,1)  = " << std::bitset<8>(std::rotr(i8, 1)) << '\n';
    std::cout << "rotr(i8,9)  = " << std::bitset<8>(std::rotr(i8, 9)) << '\n';
    std::cout << "rotr(i8,-1) = " << std::bitset<8>(std::rotr(i8, -1)) << '\n';

    //9.countl_zero example从最高位起计量连续的 0 位的数量
    for (const std::uint8_t i : {0, 0b11111111, 0b11110000, 0b00011110})
        std::cout << "countl_zero( " << std::bitset<8>(i) << " ) = "
        << std::countl_zero(i) << '\n';

    //10.countl_one example从最高位起计量连续的 1 位的数量
    for (const std::uint8_t i : {0, 0b11111111, 0b01111111, 0b11100011})
        std::cout << "countl_one( " << std::bitset<8>(i) << " ) = "
        << std::countl_one(i) << '\n';

    //11.countr_zero example从最低位起计量连续的 0 位的数量
    for (const std::uint8_t i : {0, 0b11111111, 0b00011100, 0b00011101})
        std::cout << "countr_zero( " << std::bitset<8>(i) << " ) = "
        << std::countr_zero(i) << '\n';

    //12.countr_one example从最低位起计量连续的 1 位的数量
    for (const std::uint8_t i : {0, 0b11111111, 0b11111110, 0b11100011})
        std::cout << "countr_one( " << std::bitset<8>(i) << " ) = "
        << std::countr_one(i) << '\n';

    //13.popcount example计量无符号整数中为 1 的位的数量
    for (const std::uint8_t x : {0, 0b00011101, 0b11111111})
        std::cout << "popcount( " << std::bitset<8>(x) << " ) = "
        << std::popcount(x) << '\n';

    return 0;
}

运行结果:

参考

https://learn.microsoft.com/zh-cn/cpp/standard-library/bit-functions?view=msvc-170#bit_cast

https://zh.cppreference.com/w/cpp/header/bit

相关推荐
飞翔的薄荷3 天前
C++20 时间转本地时间,时间转字符串以及字符串转时间的方法
算法·c++20
何曾参静谧9 天前
「C/C++」C++20 之 #include<ranges> 范围
c语言·c++·c++20
年轻的古尔丹10 天前
【C++ 20进阶(1):模块导入 import】
c++20·c++ module·c++ import·c++ export·c++ 模块
fengqiao199916 天前
C++ 20 Concept
c++20
好看资源平台16 天前
C++卓越:全面提升专业技能的深度课程(第一章第一课C++17与C++20概述)
c++·算法·c++20
charlie11451419116 天前
C++20 STL CookBook读书笔记1
开发语言·c++·msvc·c++20
fengbingchun16 天前
C++20中头文件syncstream的使用
c++20
barbyQAQ20 天前
C++20投影、范围与视图
java·jvm·c++20
guangcheng0312q24 天前
C++20那些事之constexpr与comma expr
java·开发语言·c++20
dotdotyy25 天前
C++基础补充(03)C++20 的 std::format 函数
c++·c++20