int main(){
ll a=pow(2,32);
cout <<a<<endl;
cout << (-1<<1)<<endl;
printf("%x",-1<<1);
}
对于上面的代码,我得到以下输出:
4294967296
-2
fffffffe
十进制中的 4294967296
等于十六进制的fffffffe
,基本上是2^32
。为什么printf和cout表现不同?这种转变究竟是如何运作的?
答案 0 :(得分:4)
printf
格式标志%x
表示以十六进制打印整数值。
还有一个流操作器来实现这一点(std::hex
),但你没有使用它。当您向没有操纵器的流输出积分值时,它将以基数10输出。
See here有关printf
格式标志的更多信息,and here有关流操作符的信息。
移位运算符<<
的工作原理如C ++ 03标准(14882:2003)所述:
1 /移位运算符&lt;&lt;和&gt;&gt;从左到右组。 移位表达: 添加剂的表达 shift-expression&lt;&lt;添加剂的表达 shift-expression&gt;&gt;添加剂的表达
操作数应为整数或枚举类型和整数 促销活动。结果的类型是 提升左操作数。如果右操作数,则行为未定义 是负的,或大于或等于的长度 提升左操作数。
2 / E1的值<&lt; E2是E1(解释为位模式) 左移E2位位置;空位是零填充的。如果E1有 无符号类型,结果的值是E1乘以 数量2增加到功率E2,减少模数ULONG_MAX + 1,如果E1 类型为unsigned long,否则为UINT_MAX + 1。
[注意:标题中定义了常量ULONG_MAX和UINT_MAX )。 ]
在您的情况下,二进制中的值-1
在每个位中都是1
。对于32位值,则:
11111111 11111111 11111111 11111111
如果使用<<
将此位向左移1位,则会得到:
11111111 11111111 11111111 11111110
在10的基数是-2。由于操作-1<<1
使用LHS的负数,因此整个表达式是带符号(非符号)类型。
答案 1 :(得分:1)
首先,
十六进制的fffffffe,基本上是2 ^ 32
错了。 FFFFFFFE = 4294967294,为2 ^ 32 - 2(对于无符号整数),或-2(对于2的补码中的32位有符号整数)。
其次,printf("%x", ...)
将打印无符号十六进制整数(即unsigned int
),在大多数现代系统上为32位。 long long a = 2 << 32
需要一个64位整数来正确存储它(或者更准确地说,至少是一个33位整数),所以当你使用cout << a
时,你正在调用ostream& operator<<(ostream&, long long)
,有合适的类型。也就是说,由于printf说明符使用的类型与C ++ operator<<
重载使用的强类型,您遇到了溢出问题。
答案 2 :(得分:1)
此代码调用undefined behavior,因为您尝试左移为负数,the draft C++11 Standard部分5.8
Shift运算符表示(强调我的):
E1的值<&lt; E2是E1左移E2位位置;腾空 位是零填充的。如果E1具有无符号类型,则为 结果是E1×2E2,比最大值减少一个模数 在结果类型中可表示。否则,如果 E1具有签名类型 和非负值,E1×2E2可在结果中表示 type,那就是结果值;否则,行为是 未定义强>
对于draft C99 standard部分6.5.7
按位移位运算符
未定义的行为指定无效的转换说明符到printf
,您指定的%x
期望无符号int 但结果是签名。 7.19.6.1
部分中的 C99草案 fprintf函数段 9 表示:
如果转换规范无效,则行为未定义.248)如果任何参数不是相应转换规范的正确类型,则行为为 未定义。
答案 3 :(得分:0)
%x
格式化输出以十六进制显示值,因此您应该将std::hex
传递给cout
以执行相同的操作:
std::cout << std:::hex << (-1<<1) << endl;
^^^^^^^^^
答案 4 :(得分:0)
这将产生正确的相同答案,因为您需要告诉它以十六进制打印
cout << hex<<(-1<<1)<<endl;
printf("%x",-1<<1);
答案 5 :(得分:0)
%x是十六进制,因为cout只是直接输出数字(int) -1是0xFFFFFFFF,向左移动你必须加0 即所以最后的F(二进制是1111变为1110即E 其他人更清楚地回答你的观点我想......
答案 6 :(得分:0)
为了便于阅读,我们使用带符号的8位整数:
-1 bitwise is 11111111
现在左移1:
-1 << 1
你得到:
11111110 which is -2
但是,使用转化说明符%x
会让printf()
将11111111
作为取消 - 签名,以便打印出fe
。
答案 7 :(得分:0)
第一种情况有效:pow(2,32)
返回精确值2 32 作为double
,当您将其转换为long long
时,它仍然是准确的(I {I}}我假设这就是神秘的ll
类型。使用cout
打印此内容非常有效。
在(-1<<1)
的情况下,左移一个负数会产生未定义的行为。即使编译器确实将其定义为-2(大多数情况下),它也是未定义的行为,用于传递负数以便与printf
的{{1}}说明符一起使用(需要无符号类型)。