什么是“int i = 1;为什么(i> = 60 * 60 * 1000/1 * 1000)”是真的吗?

时间:2011-07-14 06:14:05

标签: c type-conversion

首先,定义两个没有括号的常量表达式是我的错:

#define BIG_INTERVAL 60 * 60 * 1000
#define SMALL_INTERVAL 1 * 1000

int i = 1;

if (i >= BIG_INTERVAL / SMALL_INTERVAL - 1)
{
    printf("Oops!\n");
}

宏扩展后的if语句为if(i >= 60 * 60 * 1000 / 1 * 1000 - 1)

这不是我的意图。但是如果我写if (i >= 3600000000 - 1),我会发现一些奇怪的东西。这是错误的。

60 * 60 * 1000 / 1 * 1000 - 1是什么类型的? int

9 个答案:

答案 0 :(得分:69)

int上的所有运营商都返回int。是的,60 * 60 * 1000 / 1 * 1000 - 1int。但是3599999999的预期结果对于int而言太大了,因此表达式实际上计算为-694967297(假设32位int和2的补码)。

文字3600000000不会发生这种情况,因为大于INT_MAX的整数文字属于 可以保存完整值的类型。

答案 1 :(得分:42)

60 * 60 * 1000/1 * 1000 - 1 = 3600000 * 1000 - 1,溢出int类型,因此结果可以是任何东西(在你的情况下它是负数,但不一定是)。

要实现你想要的东西():

#define BIG_INTERVAL (60 * 60 * 1000)
#define SMALL_INTERVAL (1 * 1000)

答案 2 :(得分:12)

这是我的测试结果:

60 * 60 * 1000 / 1 * 1000 will result to -694967296

(60 * 60 * 1000) / (1*1000) will result to 3600

您的操作存在问题,即计算的优先级。

您可能需要考虑查看C ++运算符优先级http://msdn.microsoft.com/en-us/library/126fe14k%28v=vs.80%29.aspx。你会找到结果变成-694967296的原因,我觉得溢出的效果。

答案 3 :(得分:9)

如果使用int为64位的编译器,您会发现表达式的结果为false。如果使用int为32位或16位的编译器,则表达式具有未定义的行为,因为有符号整数的溢出不必包含。可能你的确只是环绕,但它并没有。

3600000000是在编译时可见的常量,因此如果int只有32位,那么编译器必须选择long long(或者只要long为64位)。所以你的另一个表达式用足够的位来计算,以避免溢出,结果是正确的。

答案 4 :(得分:4)

可能是你的字符大小超过了2147m左右的签名,这意味着如果你翻过代表,那就变成了负数。正如其他答案所指出的,当扩展时,除法不做任何事情,因此用括号

包围宏定义

答案 5 :(得分:2)

你最有可能超出有符号int的有效值范围--3600000000是一个相当大的数字!

发生这种情况时,该值将成为int数据类型的最小负值。

这将导致您的陈述成立。

答案 6 :(得分:1)

该表达式的每个参数都是一个整数,因此结果将是一个整数。

答案 7 :(得分:1)

我认为你对Macros的运作方式感到困惑。您没有使用这些宏中的值,而是使用方程本身。我认为这是你的困惑所在。我认为您应该在宏中使用括号或不使用宏。

答案 8 :(得分:0)

我没有看到任何人提到的一点是,即使完全括起宏定义并不能完全解决问题。

问题是:

#define BIG_INTERVAL 60 * 60 * 1000

(提问者承认缺少括号是个问题)。但即便如此:

#define BIG_INTERVAL (60 * 60 * 1000)

每个常量(60,60和1000)绝对可以表示为int,但产品是3600000,而语言只保证INT_MAX >= 32767

该语言表示大整数常量的大小足以保存其值(例如,100000可以是int类型或long int类型,具体取决于这些类型的范围),但它没有表达式,甚至是常量表达式的规则。

你可以像这样解决这个问题:

#define BIG_INTERVAL (60L * 60L * 1000L)

但即使它不需要,它也会使其成为long类型。

关于运算符优先级问题,这是我最喜欢的例子:

#include <stdio.h>

#define SIX 1+5
#define NINE 8+1

int main(void)
{
    printf("%d * %d = %d\n", SIX, NINE, SIX * NINE);
    return 0;
}

输出当然是

6 * 9 = 42

(见道格拉斯亚当斯)。