2011-07-07 51 views
8

对此有一个窥视。编译器抱怨说我有一个整数溢出,但是当我查看C89标准的整数提升规则以及该表达式中的值时,似乎没有溢出。C积分溢出?

[email protected]:~$ cat test.c 
#include <stdio.h> 
#include <inttypes.h> 

const uint32_t value = 
    (0x7F-0x00 + 1) * (256 + 256*256 + 256*256*256) + 
    (0xDF-0xC2 + 1) * (256 + 256*256 + 256*256*256); 

int 
main(void) 
{ 
    printf("value = %"PRIu32"\n", value); 
    return 0; 
} 
[email protected]:~$ gcc -std=c89 -pedantic -Wall -Wextra test.c 
test.c:5: warning: integer overflow in expression 
test.c:6: warning: integer overflow in expression 
test.c:6: warning: overflow in constant expression 
[email protected]:~$ ./a.out 
value = 2661195264 
[email protected]:~$ 

此外,谷歌确认2661195264的答案是该表达的正确值! (See this link

那么,程序如何在有整数溢出时产生正确的值?更重要的是,该表达式中的整数溢出是如何开始的?

+0

也许它使用signed int而不是unsigned,那么尽管计算了正确的无符号值,但在签名操作中会发生溢出。 – Nobody

回答

14
(0x7F-0x00 + 1) * (256 + 256*256 + 256*256*256) 

具有值2155905024;最大可表示签署 32位int2147483647,所以你确实产生了溢出。无论如何,它恰巧给了你预期的结果(你很幸运)。

请注意,您的整个初始化程序有签名类型(特别是类型int),因为没有文字是后缀。该表达式被评估为带符号的整型,然后将结果值转换为无符号整数。

+2

...并注意'int'只需要16位,所以即使是'256 * 256'也可能是溢出。你可以通过为每个常量使用'256UL'而不是'256'来解决这个问题。 – caf

2

虽然你的常量都是正数,但它们仍然是有符号整数。您溢出了有符号整数的范围。将结果分配给变量时,结果将转换为无符号数据作为最后一步。

加法,减法和乘法的位模式在有符号和无符号操作之间是相同的。虽然编译器在这种情况下不需要提供正确的答案,但这只是最自然的结果。