2012-04-01 122 views
13

为什么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。 谢谢。

+6

...因为d == c/1000。这是真实的生活吗? – outis 2012-04-01 13:31:56

+2

@crushanator其实a也不等于d。你看到了吗? – 2012-04-01 13:34:02

+3

为什么在这个例子中1不等于2:'int a = 1; int b = 2;'? – 2012-04-01 13:34:08

回答

5

它看起来像你使用的平台,其中intlong具有相同的大小。 (我的事实,如果long能够容纳所有的unsigned int你不会看到你所看到的行为有效的值推断出这一点。)

这意味着,在表达a*z,既az转换为unsigned long,结果的类型为unsigned long。 (ISO/IEC 14882:2011,5 [expr]/9 ...“否则,两个操作数都应转换为与带符号整数类型的操作数类型相对应的无符号整数类型”)。将这个表达式从unsigned long转换为long,并且在您的情况下,这会导致实现定义的结果(该结果恰好为负),因为a*z的正值无法在签名的long中表示。在c/1000,1000转换为longlong除法执行(无双关意图)导致long(这恰好是负数)并存储到d

在表达式a*z/10001000int类型的表达式)转化为unsigned long和在两个unsigned long之间执行的除法产生了阳性结果。该结果可表示为long,并且该值在转换为long并存储到b时未改变。

+0

这实际上就是MS C编译器的情况。 – Inisheer 2012-04-01 13:48:32

+0

签名溢出是未定义的行为,但方式。 – 2012-04-01 13:49:02

+1

@KerrekSB:是的,但在这个例子中没有签名溢出。 – 2012-04-01 13:51:02