概述
C++ 20在位操作方面带来了显著的改进和新功能,旨在让位级别的操作更加高效、安全且易于理解。这些改进不仅增强了标准库中的位操作支持,还通过引入新的算法和类型提升了位操作的表达力。C++ 20中这些改进的位操作避免了直接使用位运算符进行复杂的位操作,降低了出错的可能性,提高了代码的可读性和可维护性。
位计数函数
位计数函数位于<bit>头文件中,这些函数对于需要高效地统计二进制表示中1的个数或者0的分布情况的场景非常有用,特别是在算法、数据压缩、通信协议处理等领域。
std::popcount:用于计算一个整数中二进制位为1的数量,对于统计比特流中的“有效位”数量非常有用。
std::countl_zero:用于计算一个整数从最高有效位(MSB)开始到第一个1之间的连续0的数量。
std::countr_zero:用于计算一个整数从最低有效位(LSB)开始到第一个1之间的连续0的数量。
位计数函数的具体使用,可参考下面的示例代码。
#include <bit>
#include <iostream>
using namespace std;
int main()
{
unsigned int uiNumber = 0b1010'1010'0000'1010'0000u;
// 输出:6
cout << popcount(uiNumber) << endl;
// 输出:12
cout << countl_zero(uiNumber) << endl;
// 输出:5
cout << countr_zero(uiNumber) << endl;
return 0;
}
位移动函数
位移动函数也位于<bit>头文件中,这些函数极大地简化了对整数类型的循环位移操作。循环位移操作能够保持数据的完整性,特别适合那些需要在有限空间内循环移动数据的场景,而不需要考虑数据溢出问题。
std::rotl(T x, int n):循环左移,将x的二进制表示向左移动n位,超出的位移到右边。
std::rotr(T x, int n):循环右移,将x的二进制表示向右移动n位,超出的位移到左边。
位移动函数的具体使用,可参考下面的示例代码。
#include <bit>
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
unsigned int uiNumber = 0b1110'0000'0000'1010'1010'0000'1010'0000u;
// 输出:00000000101010100000101000001110
cout << bitset<32>(rotl(uiNumber, 4)) << endl;
// 输出:00001110000000001010101000001010
cout << bitset<32>(rotr(uiNumber, 4)) << endl;
return 0;
}
std::bit_cast
std::bit_cast允许我们将一个对象的位模式直接无损地转换为另一个类型,前提是这两个类型具有相同的大小。这意味着,我们可以将一个类型的实例“重新解释”为另一个类型,而无需涉及任何构造函数、赋值操作或类型转换构造函数。
在下面的示例代码中,我们通过std::bit_cast<TDataInfo>,将uiNumber的位模式直接转换到TDataInfo结构体中。这意味着,原始整数的低16位(0x5678)被视为usNumber1,高16位(0x1234)被视为usNumber2。
#include <bit>
#include <iostream>
#include <format>
using namespace std;
typedef struct _TDataInfo
{
unsigned short usNumber1;
unsigned short usNumber2;
}TDataInfo;
int main()
{
unsigned int uiNumber = 0x12345678;
TDataInfo dataInfo = bit_cast<TDataInfo>(uiNumber);
// 输出:0x5678
cout << format("0x{:x}", dataInfo.usNumber1) << endl;
// 输出:0x1234
cout << format("0x{:x}", dataInfo.usNumber2) << endl;
return 0;
}