当x = 0x80000000时,〜(x-1)和~x + 1之间的差异

shi*_*ley 8 c bit-shift

我使用的语言是C.x和n的类型是int.

我有一个行代码如下

  printf("x=%x,n=%d,first=%x,second=%x\n",x,n,((~(x+0xffffffff))>>n),((~x+1)>>n));
Run Code Online (Sandbox Code Playgroud)

它显示了x,n的值和两个移位x的补数的n位的方法.当x = 0x80000000时,〜(x + 0xffffffff)= 0x8000000,~x + 1 = 0x80000000,但当将这两个移位n位时,结果是不同的.

顺便说一下,如果我把0xffffffff改为~1 + 1(即〜(x +(~1 + 1)),结果与~x + 1相同

我想知道为什么会这样.谢谢.

Dan*_*her 4

Pavan Manjunath 现已删除的答案对于一种情况有正确的答案,假设它int像往常一样是 32 位类型。整数常量

0xffffffff
Run Code Online (Sandbox Code Playgroud)

具有值2^32 - 1并且不能用 表示int,但可以用 表示unsigned int。所以它的类型是unsigned int(6.4.4.1)。因此x转换unsigned int为加法,并且

((~(x+0xffffffff))>>n)
Run Code Online (Sandbox Code Playgroud)

评估为

((~(0x80000000u + 0xffffffffu)) >> n)
((~0x7fffffffu) >> n)
(0x80000000u >> n)
Run Code Online (Sandbox Code Playgroud)

值为2^(31-n)if (如果超出该范围,0 <= n < 32则为未定义行为)。n

对于另一种情况,ouah 的答案是正确的,当x = 0x80000000是 时int~0x8000000 = 0x7fffffff = INT_MAX并且INT_MAX + 1是有符号整数溢出的未定义行为。

然而,常见的行为是环绕,然后加法的结果是有符号整数0x80000000,负整数的右移是实现定义的行为(6.5.7)。常见的是使用符号扩展进行移位,这将产生结果,然后由转换说明符-2^(31-n)将其解释为unsigned int带有值的。2^32 - 2^(31-n)printf%x