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

时间:2012-06-04 13:47:00

标签: 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));

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

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

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

3 个答案:

答案 0 :(得分:4)

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

0xffffffff

的值为2^32 - 1int无法表示,但可以表示为unsigned int。所以它的类型是unsigned int(6.4.4.1)。因此x转换为unsigned int以进行添加,

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

评估为

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

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

对于另一种情况,ouah的回答是正确的,当x = 0x80000000int时,~0x8000000 = 0x7fffffff = INT_MAXINT_MAX + 1是未定义的行为,因为有符号整数溢出。

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

答案 1 :(得分:1)

  

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

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

 ~x+1

是未定义的行为。 x = 0x80000000表示~x == 0x7FFFFFFF == INT_MAXINT_MAX + 1表示未定义的行为。因此~x + 1可以是0x80000000或其他任何内容。

这个表达式:

~(x+0xffffffff)
另一方面,

被定义(C中的0xffffffffunsigned int并且等于0x80000000。它实际上是定义的,因为0xffffffffunsigned int,无符号整数从不在C标准意义上溢出。

这意味着这句话:

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

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

答案 2 :(得分:0)

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

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

在0x7FFFFFFF上使用'〜'运算符会产生逐位完整,或0x80000000

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

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

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