所以我写了一个小实验,用c语言和64位机器测试下溢和溢出。对于int类型,最小/最大值为:
int tmax = 2147483647;
int tmin = -2147483648;
我知道“两个的互补”是如何工作的,这不是我的问题。
所以我想,如果我做了一些负面的事情会怎么样?即:
int tmin = -2147483648;
int negativeTmin = -tmin;
结果还是不知道。(也就是说,negativeTmin将是-2147483648)
我的问题是为什么?因为正数2147483648不能用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
最佳答案
正如其他人在这里所说,从技术上讲,您所做的事情会导致未定义的行为,因为C中有符号整数的溢出或下溢会导致未定义的行为。
另一方面,在大多数英特尔系统中,整数溢出或下溢只是环绕整数值并设置一些处理器标志,以便将来的指令可以检测溢出。在这些系统上,有理由问-为什么在计算-Tmin时会得到Tmin?
在有符号二的补码系统中,最好注意表达式-x
等同于~x + 1
。假设你有Tmin,它看起来是这样的:
10000000 00000000 00000000 00000000
如果计算~Tmin,则得到
01111111 11111111 11111111 11111111
这正好是Tmax。如果你再加上一个,你会得到一个巨大的波纹,传播到最后,产生
10000000 00000000 00000000 00000000
我们就是从这开始的。所以这就是为什么你可能会看到Tmin回来。
另一种方法是:你知道有符号32位整数的Tmin是-231。-Tmin的值应该是这样一个值:Tmin+-Tmin=0(mod 232)。那么在[-231231231-1]范围内的哪个值恰好有这个属性?是-231,这就是为什么Tmin=-Tmin。
所以,对你的问题最好的回答可能是“技术上你所做的是未定义的行为,但是在一个合理的英特尔系统和一个没有设置为进行激进优化的编译器上,它归结于32位整数算术如何工作以及如何定义否定的机制。”