为什么d
不等于b
在这个例子中?奇怪的计算结果
unsigned int z = 176400;
long a = -4;
long b = a*z/1000; //b=4294261
long c = a*z; // c=-705600
long d = c/1000; // d =-705
我使用Visual Studio 2008,Windows XP,core2duo。 谢谢。
为什么d
不等于b
在这个例子中?奇怪的计算结果
unsigned int z = 176400;
long a = -4;
long b = a*z/1000; //b=4294261
long c = a*z; // c=-705600
long d = c/1000; // d =-705
我使用Visual Studio 2008,Windows XP,core2duo。 谢谢。
它看起来像你使用的平台,其中int
和long
具有相同的大小。 (我的事实,如果long
能够容纳所有的unsigned int
你不会看到你所看到的行为有效的值推断出这一点。)
这意味着,在表达a*z
,既a
和z
转换为unsigned long
,结果的类型为unsigned long
。 (ISO/IEC 14882:2011,5 [expr]/9 ...“否则,两个操作数都应转换为与带符号整数类型的操作数类型相对应的无符号整数类型”)。将这个表达式从unsigned long
转换为long
,并且在您的情况下,这会导致实现定义的结果(该结果恰好为负),因为a*z
的正值无法在签名的long
中表示。在c/1000
,1000
转换为long
和long
除法执行(无双关意图)导致long
(这恰好是负数)并存储到d
。
在表达式a*z/1000
,1000
(int
类型的表达式)转化为unsigned long
和在两个unsigned long
之间执行的除法产生了阳性结果。该结果可表示为long
,并且该值在转换为long
并存储到b
时未改变。
这实际上就是MS C编译器的情况。 – Inisheer 2012-04-01 13:48:32
签名溢出是未定义的行为,但方式。 – 2012-04-01 13:49:02
@KerrekSB:是的,但在这个例子中没有签名溢出。 – 2012-04-01 13:51:02
...因为d == c/1000。这是真实的生活吗? – outis 2012-04-01 13:31:56
@crushanator其实a也不等于d。你看到了吗? – 2012-04-01 13:34:02
为什么在这个例子中1不等于2:'int a = 1; int b = 2;'? – 2012-04-01 13:34:08