1使用〜在C / C ++中的补码

时间:2014-06-01 10:03:04

标签: c++ c unsigned signed ones-complement

我正在使用Visual Studio 2013.
最近我尝试了~运算符1的补码:

int a = 10;
cout << ~a << endl;

输出为-11

但是

unsigned int a = 10;
cout << ~a << endl;

输出为4294967296

在签名-11的情况下,我不明白为什么输出为int。 请帮我解决这个困惑。

4 个答案:

答案 0 :(得分:16)

当你将数字10放入32位有符号或无符号整数时,你得到

0000 0000  0000 0000  0000 0000  0000 1010

当你否定它时,你会得到

1111 1111  1111 1111  1111 1111  1111 0101

这32位表示4294967285为无符号整数,或-11为有符号整数(您的计算机表示负整数为Two's complement)。它们还可以表示32位浮点数或4个8位字符。

比特没有任何“绝对”含义。它们可以代表任何东西,具体取决于你“看”它们的方式(它们具有哪种类型)。

答案 1 :(得分:4)

~运算符对其参数执行ones-complement,无论参数是有符号整数还是无符号整数都无关紧要。它只是翻转所有位,所以

0000 0000 0000 1010 (bin) / 10 (dec)

变为

1111 1111 1111 0101 (bin)

(其中,据推测,这些数字是32位宽 - 我省略了16个0和1。)

cout将如何显示结果?它查看原始类型。对于 signed 整数,最重要的位是其符号。因此,结果始终是否定(因为10中最重要的位是0)。要将负数显示为正数,需要二进制补码:反转所有位,然后加1.例如,-1,二进制111..111,显示为(反转)000..000然后+1:000..001。结果:-1

将此应用于10的{​​{1}}的补码,您得到111..110101 - &gt;反转为000...001010,然后添加1。结果:-11。

对于无符号号码,cout不会(自然地)执行此操作,因此您得到一个大数字:最大可能的整数减去原始号码。

答案 2 :(得分:1)

在内存中,两种情况下都存储了4294967285(4294967296正确是一个错字,33位?),这个数字的含义取决于你使用的标记:

  • 如果已签名,则该号码为-11。
  • 如果它未签名,那么它是4294967285

对相同数字的不同解释。

您可以通过强制转换将其重新解释为无符号,结果相同:

int a = 10;
cout << (unsigned int) ~a << endl;

答案 3 :(得分:1)

试试这个

unsigned int getOnesComplement(unsigned int number){

unsigned onesComplement = 1;
if(number < 1)
    return onesComplement;
size_t size = (sizeof(unsigned int) * 8 - 1) ;
unsigned int oneShiftedToMSB = 1 << size;

unsigned int shiftedNumber = number;
for ( size_t bitsToBeShifted = 0; bitsToBeShifted < size; bitsToBeShifted++){
    shiftedNumber = number << bitsToBeShifted;
    if(shiftedNumber & oneShiftedToMSB){
        onesComplement = ~shiftedNumber;
        onesComplement = onesComplement >> bitsToBeShifted;
        break;
    }
}
return onesComplement;
}