为什么std::bitset建议有更多可用位数,而sizeof所述的位数较少?

15

我正在使用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

为什么会有这么多的1?我本来期望只有32个1,前面补充0。但实际上数量是两倍,发生了什么事情?

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

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

$:000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111

4
顺便说一下,对于完全遵循sizeof()和CHAR_SIZE标准,我要给你点赞。大多数人都认为这些东西是理所当然的,尤其是后者。 - user4442671
谢谢你详细的回答,现在我明白了。我目前正在为即将到来的面试做准备,所以我正在尽可能多地学习关于这些事情的工作原理,很高兴我走在正确的道路上! - jonthalpy
2个回答

20
< p > std::bitset 的构造函数接受一个 unsigned long long,当您尝试将 -1(即 int 中的 ~0)赋值给 unsigned long long 时,您会得到 8 个字节(64 位)的 1。

这在使用 unsigned int 时不会发生,因为您将赋值为 4294967295 的值,而不是 -1,这是 unsigned long long 中的 32 个 1。


8
值得一提的是术语“零扩展”和“符号扩展”,这样人们就知道如果想进一步阅读,该搜索什么。 - ildjarn
3
由于该问题非常注重平台独立性(甚至不假设CHAR_BIT为8),因此您可能需要提到~0 == -1仅适用于二进制补码表示。 - Angew is no longer proud of SO
1
嗯,我不明白你是如何得到2147483647的,你是不是想说4294967295? - pipe
实际上,unsigned int 的最大值是 4294967295(32个1对应于 2^32 - 1)。 - cute_ptr
唉,这就是我在周日晚上回答问题的后果...已经修复了。谢谢! - user4442671

4

当你写下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(因为你有一个负值,符号扩展将其保持不变,并通过在左侧填充32个1来实现)。
因此,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个最左侧的位)则被初始化为0。因此当您打印时,会得到以下结果:
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(因为你有一个正值,符号扩展将其保持为正值,通过填充32个最左边的0来实现)。
所以,std::bitset 构造函数获得的 unsinged long long 表示为32个0,后跟32个1。它将使用32个0后跟32个1初始化你要求的96个位中的64个最右边的位。剩余的32个最左边的位(96位中的前32位)被初始化为0。因此,当你打印它时,你会得到(64个0后跟32个1):
000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接