为什么 std::bitset 建议的可用位比 sizeof 说的多?

Why does std::bitset suggest more available bits than sizeof says there are?

我正在用 C++ 解决一些简单的位操作问题,并在尝试可视化我的步骤时遇到了这个问题。我知道分配给不同原始类型的位数可能因系统而异。对于我的机器,sizeof(int) 输出 4,所以我有 4 char 位作为我的值。我现在也知道一个字节的定义通常是8位,但不一定如此。当我输出 CHAR_BIT 时,我得到 8。因此,我希望我的 int 值总共有 32 位。

然后我可以继续将 int 的二进制值打印到屏幕上:

int max=~0; //All my bits are turned on now
std::cout<<std::bitset<sizeof(int)*CHAR_BIT>(max)<<std::endl;

$:11111111111111111111111111111111

不过,如果我愿意,我可以增加位集大小:

int max=~0;
std::cout<<std::bitset<sizeof(int)*CHAR_BIT*3>(max)<<std::endl;

$:000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111

为什么有这么多?我原以为只有 32 个,用零填充。反而是两倍多,这是怎么回事?

当我用 unsigned int 重复实验时,它的大小与 int 相同,多余的不会出现:

unsigned int unmax=~0;
std::cout<<std::bitset<sizeof(unsigned int)*CHAR_BIT*3>(unmax)<<std::endl;

$:000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111

std::bitset 的构造函数采用 unsigned long long,当您尝试将 -1(这就是 int 中的 ~0)分配给一个unsigned long long,你得到 8 个字节(64 位),相当于 1。

unsigned int 不会发生这种情况,因为您分配的值是 4294967295 而不是 -1,后者在 unsigned long long

中是 32 个 1

写成int max=~0;时,max就是32位补1,解释成整数就是-1

写的时候

std::bitset<sizeof(int)*CHAR_BIT>(max)
// basically, same as
std::bitset<32>(-1)

您需要记住 std::bitset 构造函数采用 unsigned long long。因此,您传递给它的 -1 被转换为 -1 的 64 位表示形式,即 64 位全部用 1 填充(因为您有一个负值,符号扩展保持它原样,通过用 1 填充最左边的 32 位)。

因此,std::bitset的构造函数得到一个全为1的unsigned long long,并将你要求的32位初始化为1。所以,当你打印它时,你会得到:

11111111111111111111111111111111

然后,当你写:

std::bitset<sizeof(int)*CHAR_BIT*3>(max)
// basically, same as
std::bitset<96>(-1)

std::bitset 构造函数将用您传递的 unsigned long long 的值初始化您要求的 96 的最右边的 64 位,因此这 64 位用 1 填充。其余位(最左边的 32 位)用零初始化。所以当你打印它时,你会得到:

000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111

另一方面,当您编写 unsigned int unmax=~0; 时,您会将所有 1 分配给 unsigned int,因此您会得到 UINT_MAX.

然后,当你写:

std::bitset<sizeof(unsigned int)*CHAR_BIT*3>(unmax)
// basically, same as
std::bitset<96>(UINT_MAX)

您传递的 UINT_MAX 被转换为 64 位表示,即最右边的 32 位填充 1,其余全为 0(因为您有一个正值,符号扩展保持它原样, 通过用 0 填充最左边的 32 位)。

所以 std::bitset 构造函数得到的 unsinged long long 表示为 32 个 0,然后是 32 个 1。它将用 32 个 0 和后跟 32 个 1 初始化您要求的 96 的最右边的 64 位。剩余的 32 个最左边的位(共 96 个)用零初始化。所以当你打印它时,你会得到(64个0后跟32个1):

000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111