我认为首先从0开始400*400=160000转换为28928并以循环方式转换为160000时间为int类型(比如sizeof(int)= 2字节),假设它如下:
然后将28928除以400,其中得到72,结果随变量的类型而变化.我的假设是正确的还是有其他解释?
Mys*_*ial 42
假设您使用的是一个可怕的老式编译器,其中int只有16位.那么是的,你的分析是正确的.*
400 * 400 = 160000
// Integer overflow wrap-around.
160000 % 2^16 = 28928
// Integer Division
28928 / 400 = 72 (rounded down)
Run Code Online (Sandbox Code Playgroud)
当然,对于较大的数据类型,这种溢出不会发生,所以你会回来400.
*仅对无符号整数类型保证此环绕行为.对于有符号整数,它在C和C++中是技术上未定义的行为.
在许多情况下,有符号整数仍将表现出相同的环绕行为.但你不能指望它.(因此,保证带有带符号的16位整数的示例保持不变.)
虽然很少见,但这里有一些示例,其中有符号整数溢出未按预期包装:
看起来你猜对了.
如果int是16位类型,那么它的行为与您描述的完全相同.您的操作按顺序进行,400*400产生160000,即10 0111 0001 0000 0000
当你将它存储在16位寄存器中时,顶部"10"将被切断,你最终得到0111 0001 0000 0000(28,928)....你猜对了.
你在哪个编译器/平台上构建它?典型的桌面至少是32位,所以你不会看到这个问题.
更新#1
注意:这是用您的特定编译器解释您的行为的原因.正如许多其他人很快指出的那样,不要假设所有编译器都采用这种方式.但你的具体肯定是.
为了完成下面评论的答案,您看到这种行为的原因是大多数主要编译器在这些情况下优化速度,并且在简单算术运算后不添加安全检查.因此,如上所述,硬件根本没有空间存储这些额外的位,这就是您看到"循环"行为的原因.
您必须要知道的第一件事是,在C中,整数溢出是未定义的行为.
(C99,6.5.5p5)"如果在评估表达式期间发生异常情况(即,如果结果未在数学上定义或在其类型的可表示值范围内没有),则行为未定义."
C说得非常清楚并在此重复:
(C99,3.4.3p3)"示例未定义行为的示例是整数溢出的行为."
请注意,整数溢出仅将有符号整数视为无符号整数永不溢出:
(C99,6.2.5p9)"涉及无符号操作数的计算永远不会溢出,因为无法用结果无符号整数类型表示的结果是以一个大于可由结果表示的最大值的数量的模数减少的.类型."
你的声明是这样的:
int i = 400 * 400 / 400;
Run Code Online (Sandbox Code Playgroud)
假设int在你的平台上的16位和符号表示为二进制补码, 400 * 400等于160000它不能表示为一个int,INT_MAX值是32767.我们存在整数溢出,实现可以做任何想做的事情.
通常,在此特定示例中,编译器将执行以下两种解决方案之一:
400 * 400 / 400是72.400 * 400 / 400到400.这通过优秀的编译器来完成,通常是在启用优化选项时.请注意,整数溢出是未定义的行为,特定于C语言.在大多数语言(例如Java)中,它们以C语言中的无符号整数模数字大小.
在gcc有溢出总是包,还有就是-fno-strict-overflow可以启用选项(默认禁用).这是例如Linux内核的选择; 他们使用此选项进行编译,以避免出现意外情况.但这也限制了编译器不执行它可以执行的所有优化.
| 归档时间: |
|
| 查看次数: |
2948 次 |
| 最近记录: |