为什么二进制等效计算不正确?

时间:2015-09-01 09:25:16

标签: c++ binary

我编写了以下程序来输出一个整数的二进制等价物(我检查了我的系统上的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);
}

我在哪里弄错了?

3 个答案:

答案 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)

有符号整数值的典型内部存储器表示如下:

enter image description here

  

m ost s 明显 b 它(首先是右边)是符号位和signed numbers(如int)它表示数字是否为负数。   当您移动其他位时,执行符号扩展以保留数字的符号。这是通过将数字附加到数字的最重要部分来完成的。(遵循使用的特定签名数字表示的过程)。
  在无符号数字中,右侧的第一位只是所表示数字的MSB ,因此当您移位其他位时,不会执行符号扩展。

注意:这些位的枚举从 0 开始,因此1 << 31替换了您的符号位,然后向左>>的每个位移操作都会导致符号扩展。 (正如@dasblinkenlight指出的那样)

因此,解决问题的简单方法是在开始位操作之前使数字无符号(这是U1U << 31中的作用)。 (正如@Yu Hao指出的那样)

如需进一步阅读,请参阅signed number representationstwo's complement。(因为它是最常见的)