我编写了以下程序来输出一个整数的二进制等价物(我检查了我的系统上的int是4个字节)它是4个字节。但输出并不合适。代码是:
#include<iostream>
#include<iomanip>
using namespace std;
void printBinary(int k){
for(int i = 0; i <= 31; i++){
if(k & ((1 << 31) >> i))
cout << "1";
else
cout << "0";
}
}
int main(){
printBinary(12);
}
我在哪里弄错了?
答案 0 :(得分:29)
问题出在1<<31
。因为2 31 不能用32位有符号整数表示(范围-2 31 到2 31 - 1),结果是未定义的 [1] 。
修复很简单:1U<<31
。
[1]:该行为是自C ++ 14以来实现定义的。
答案 1 :(得分:8)
此表达式不正确:
if(k & ((1<<31)>>i))
int
是签名的类型,因此当您将1
移位31次时,它将成为您系统上的符号位。之后,将结果右移i
次符号 - 扩展数字,这意味着最高位保持1
s。最终得到一个如下所示的序列:
80000000 // 10000...00
C0000000 // 11000...00
E0000000 // 11100...00
F0000000 // 11110...00
F8000000
FC000000
...
FFFFFFF8
FFFFFFFC
FFFFFFFE // 11111..10
FFFFFFFF // 11111..11
要解决此问题,请将表达式替换为1 & (k>>(31-i))
。这样就可以避免因将1
移到符号位位置而导致的未定义行为 * 。
* C++14 changed the definition因此,在32位1
中向左移动int
31次不再是未定义的(谢谢,Matt McNabb,for指出这一点)。
答案 2 :(得分:4)
有符号整数值的典型内部存储器表示如下:
m ost s 明显 b 它(首先是右边)是符号位和
signed numbers
(如int
)它表示数字是否为负数。 当您移动其他位时,执行符号扩展以保留数字的符号。这是通过将数字附加到数字的最重要部分来完成的。(遵循使用的特定签名数字表示的过程)。
在无符号数字中,右侧的第一位只是所表示数字的MSB ,因此当您移位其他位时,不会执行符号扩展。
注意:这些位的枚举从 0 开始,因此1 << 31
替换了您的符号位,然后向左>>
的每个位移操作都会导致符号扩展。 (正如@dasblinkenlight指出的那样)
因此,解决问题的简单方法是在开始位操作之前使数字无符号(这是U
在1U << 31
中的作用)。 (正如@Yu Hao指出的那样)
如需进一步阅读,请参阅signed number representations和two's complement。(因为它是最常见的)