在负数上按位

时间:2013-04-20 16:57:35

标签: c

这是对负数的按位运算:

#include <stdio.h>

main()
{
    int a = -20, b = 84;
    printf("%d", (a>>(a &b)));
}

-20的二进制补码是1100二进制,84是10000100。因此a & b应为100,但答案为68,总答案为-2。

有人可以向我解释一下吗?

2 个答案:

答案 0 :(得分:4)

-20不是1100 2 。它最有可能(如果整数是32位而我们不是在谈论奇数平台),11111111111111111111111111101100 2

84不是10000100 2 。它是1010100 2

将他们加在一起:

11111111111111111111111111101100
&
00000000000000000000000001010100
=
00000000000000000000000001000100 (68 decimal)

然后你正在向右转移68个位置,这有两个问题:

  • 负整数的右移是实现定义的,你的编译器的实现是什么?
  • 按值中的位数移位或超过未定义行为的结果

在普通平台上不太可能有128位的整数。 64位整数是罕见的,但并非不可能,但对于它们68> = 64,所以你应该得到未定义的行为。

现在,这个未定义的行为可能看起来像......

如果我们的int是32位且我们在x86平台上做这个(或者类似的东西),68应该被CPU截断到5位,让你的移位数为68&amp; 31 = 4。

然后,假设SAR指令(符号保留算术右移)用于>>,我们得到(-20)SAR 4 = -2:

11111111111111111111111111101100
SAR
4
=
11111111111111111111111111111110 (-2 decimal)

答案 1 :(得分:3)

如果您使用的是Windows,它应该附带一个支持二进制文件的计算器应用程序。 这是一个很好的可靠计算源。 在那里你可以选择Word这是一个int。

左侧的所有位都是1,因此内存中会出现负数。所以-20是

  1111-1111-1110-1100
= 0xFFEC

84是:

  0000-0000-0101-0100
= 0x0054

是一个按位运算,比较检查每个位的两个传递的数字。如果两个位均为1,则结果位为1.否则为零。所以

  1111-1111-1110-1100
& 0000-0000-0101-0100
= 0000-0000-0100-0100
= 68