7

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

我有一行代码如下

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

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

顺便说一句,如果我将 0xffffffff 更改为 ~1+1(这意味着 ~(x+(~1+1)),结果与 ~x+1 相同

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

4

3 回答 3

4

Pavan Manjunath 现在删除的答案有一个案例的正确答案,假设它int像往常一样是 32 位类型。整数常量

0xffffffff

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

((~(x+0xffffffff))>>n)

评估为

((~(0x80000000u + 0xffffffffu)) >> n)
((~0x7fffffffu) >> n)
(0x80000000u >> n)

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

对于另一种情况,ouah 的答案是正确的,whenx = 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

于 2012-06-04T14:23:49.900 回答
1

当x=0x80000000,~(x+0xffffffff)=0x8000000,~x+1=0x80000000时,

在具有 32 位int(假设x类型为int)和二进制补码符号表示的系统上,此表达式:

 ~x+1

是未定义的行为。x = 0x80000000表示~x == 0x7FFFFFFF == INT_MAX并且INT_MAX + 1是未定义的行为。所以~x + 1可以0x80000000或其他任何东西。

这个表达式:

~(x+0xffffffff)

另一方面被定义(0xffffffffunsigned intC 中)并且等于0x80000000. 它实际上是定义的,因为0xffffffffisunsigned int和无符号整数在 C 标准的意义上永远不会溢出。

这意味着该声明:

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

调用未定义的行为,比较两个结果是没有意义的。

于 2012-06-04T14:02:09.357 回答
0

(假设 sizeof(int) 为 4;即 32 位有符号值)。0x80000000; // -2147483648 是最小的负整数 0xFFFFFFFF // 是 -1

将两者相加会导致从负到正的“环绕” 0x7FFFFFFF 是两者的总和(使用 int 算术),即 2147483647

在 0x7FFFFFFF 上使用 '~' 运算符会产生按位完成,或 0x80000000

如果您从任何 int 值开始并从中减去 1(或向其添加 1,没关系)足够多次,您将导致它翻转其符号。这是使用固定精度算术的一个基本问题。

在您的情况下,您不能期望在不非常注意这种限制情况的情况下混合有符号算术和按位运算符。

另请注意,使用 2 的补码算术时存在不对称性:负数比正数多一个(因为您需要表示零,这会为其余值留下奇数个其他位表示。)

于 2012-06-04T14:23:00.853 回答