所以我写了一个小实验测试下溢&溢出,使用c和64位机器。对于int类型,最小/最大值为:
int tmax = 2147483647;
int tmin = -2147483648;
我知道两个补充是如何运作的,这不是我的问题。
所以我想,如果我做了一些消极的tmin会发生什么?那就是:
int tmin = -2147483648;
int negativeTmin = -tmin;
它最终仍然是tmin。 (即,negativeTmin将为-2147483648)
我的问题是为什么会这样?由于积极的2,147,483,648不能用int表示,我理解为什么它当然不是,但它似乎并不奇怪,它并没有改变所有这一点使它成为唯一的非零int,当 - 应用于它时,它不会发生变化。我并不是说我对它应该是什么有更好的了解,我只是好奇为什么-tmin == tmin。它是否与按位运算有关,或者在计算机中如何进行减法,或者它是否默认执行此操作,因为我尝试做的是未定义的,还是其他什么?
我的代码:
#include <stdio.h>
int main() {
int tmax = 2147483647;
printf("tmax Before: %d\n", tmax);
tmax++;
printf("tmax After: %d\n\n", tmax);
int tmin = -2147483648;
printf("tmin Before: %d\n", tmin);
tmin--;
printf("tmin After: %d\n\n", tmin);
int tmin2 = -2147483648;
int negativeTmin = -tmin2;
printf("negative tmin: %d\n\n", negativeTmin);
return 0;
}
输出:
tmax之前:2147483647 tmax之后:-2147483648
tmin之前:-2147483648 tmin之后:2147483647
负tmin:-2147483648
答案 0 :(得分:3)
由于整数溢出,您的代码int tmin2 = -2147483648; int negativeTmin = -tmin2
引入了未定义的行为,因此它可能会产生任何结果。所以考虑任何规则,为什么会发生这种情况,如果它与两个补码有关,那就毫无意义,实际上是错误的。
对于未定义的行为,整数溢出是 示例,因为它在标准的&#34;未定义的行为&#34;的定义中作为示例提及。 (3.4.3 - undefined behavior):
使用不可移植或错误时的1个未定义的行为行为 程序构造或错误数据,本国际 标准没有要求
2注意可能的未定义行为包括忽略这种情况 完全具有不可预测的结果,在翻译过程中表现出色 或者以文件化的方式执行程序 环境(有或没有发出诊断信息),到 终止翻译或执行(发布a 诊断信息)。
3示例未定义行为的示例是整数上的行为 溢出。
答案 1 :(得分:3)
正如其他人在这里发布的那样,从技术上讲,你所做的事情会导致未定义的行为,因为C中有符号整数的上溢或下溢会导致未定义的行为。
另一方面,在大多数英特尔系统上,整数上溢或下溢只是围绕整数值并设置一些处理器标志,以便将来的指令可以检测到溢出。在那些系统上,当你计算-T min 时,为什么做你得到T min 是合理的?
在签名的双向补充系统中,值得注意的是表达式-x
等同于~x + 1
。所以,让我们想象你有T min ,看起来像这样:
10000000 00000000 00000000 00000000
如果你计算~T min ,你得到
01111111 11111111 11111111 11111111
这恰好是T max 。如果你向它添加一个,你会得到一个巨大的波纹携带传播一直到最后,产生
10000000 00000000 00000000 00000000
这是我们开始的。这就是为什么你可能会看到T min 回来。
另一种看待这种情况的方法:你知道签名的32位整数的T min 是-2 31 。 -T min 的值应该是一个值,使得T min + -T min = 0(mod 2 32 )。那么[-2 31 ,2 31 - 1]范围内的哪个值碰巧有这个属性?它是-2 31 ,这就是为什么T min = -T min 。
所以对你的问题的最佳答案可能是&#34;技术上你正在做的是未定义的行为,但是在合理的英特尔系统和没有设置进行积极优化的编译器上,它归结为有符号的32位整数运算如何工作以及如何定义否定的机制。&#34;
答案 2 :(得分:0)
-X是X的2s补码
这就是硬件对否定所做的事情https://c9x.me/x86/html/file_module_x86_id_216.html
INT_MIN = -2147483648 = 0x80000000
2的补充-2147483648 = 0x80000000
您可以将2的补码计算为翻转位并添加1个
请参阅https://en.wikipedia.org/wiki/Two%27s_complement。翻转位0x80000000给出0x7fffffff。
0x7fffffff + 1 = 0x80000000 = -2147483648
(gdb)p / x(int)( - 2147483648)
$ 14 = 0x80000000
(gdb)p / x(int) - ( - 2147483648)
$ 15 = 0x80000000
(gdb)p / x~(0x80000000)
$ 16 = 0x7fffffff
(gdb)p / x~(0x80000000)+ 1
$ 17 = 0x80000000
答案 3 :(得分:0)
另一种思考方式。
类型为int
的数据用32位表示。取tmin = -2147483648,然后当然是-tmin =2147483648。在二进制补码算法中, tmin 的二进制表示为
10000000 00000000 00000000 00000000
,对于 -tmin ,
0 10000000 00000000 00000000 00000000
但是只允许32位,因此截断消除了最高有效位(在这种情况下,是第一个零),我们得到了
10000000 00000000 00000000 00000000
这是 tmin 。
答案 4 :(得分:-2)
实际上我相信我刚刚意识到答案;因为我们知道2147483648不能用int表示,因此是-2147483648,所以当你做 - ( - 2147483648)以及那是2147483648时,但是不能表示如上所述那样变成-2147483648。因此为什么-tmin == tmin。