永远增加,你得到-2147483648?

Pet*_*son 5 c# loops increment integer-overflow infinite-loop

由于一个聪明而复杂的原因,我不想解释(因为它涉及以非常丑陋和hacky的方式制作计时器),我写了一些类似的C#代码:

int i = 0;
while (i >= 0) i++; //Should increment forever
Console.Write(i);
Run Code Online (Sandbox Code Playgroud)

我希望程序永远挂起或崩溃或者其他东西,但是,令我惊讶的是,在等待大约20秒左右之后,我得到了这个输出:

-2147483648
Run Code Online (Sandbox Code Playgroud)

编程已经教会了很多东西,但我仍然无法理解为什么不断增加一个数字导致它最终变成负面...这里发生了什么?

Jef*_*dge 12

在C#中,内置整数由预定义长度的一系列位值表示.对于int长度为32位的基本数据类型.由于32位只能表示4,294,967,296个不同的可能值(因为它是2 ^ 32),显然您的代码不会随着不断增加的值而永远循环.

由于int可以保存正数和负数,因此必须以某种方式对数字的符号进行编码.这是通过第一位完成的.如果第一位为1,则该数字为负.

以下是以十六进制和十进制表示的数字行上的int值:

 Hexadecimal        Decimal
 -----------    -----------
 0x80000000     -2147483648
 0x80000001     -2147483647
 0x80000002     -2147483646
    ...              ...
 0xFFFFFFFE              -2
 0xFFFFFFFF              -1
 0x00000000               0
 0x00000001               1
 0x00000002               2
     ...             ...
 0x7FFFFFFE      2147483646
 0x7FFFFFFF      2147483647
Run Code Online (Sandbox Code Playgroud)

从该图表中可以看出,代表最小可能值的位是通过将一个加到最大可能值而忽略符号位的解释而得到的.以这种方式添加带符号的数字时,它被称为"整数溢出".是否允许整数溢出或将其视为错误,可以使用C#中的checkedunchecked语句进行配置.默认是未选中的,这就是为什么没有错误发生的原因,但你在程序中得到了那个疯狂的小数字.

这种表示称为2的补语.


Chr*_*isF 8

该值溢出32位整数存储的正范围,0xFFFFFFFF以十进制为-2147483648.这意味着您以31位整数溢出.

有人指出,如果你使用unsigned int,你会得到不同的行为,因为第32位没有被用来存储数字的符号.

  • 确切地说,它没有溢出32位值,它溢出正范围,因此它有效地溢出31位.-2147483648是`0x80000000`; `0xFFFFFFFF`是-1. (6认同)
  • @David did溢出正整数32位整数的最大值。从逻辑上讲,溢出是由数据类型的约束定义的,而不是通过达到基础存储的最大填充位模式来定义的。否则,达到`0xFFFFFFFF`并加1将是真正的溢出。 (2认同)