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

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

#define BIG_INTERVAL 60 * 60 * 1000 #define SMALL_INTERVAL 1 * 1000 int i = 1; if (i >= BIG_INTERVAL / SMALL_INTERVAL - 1) { printf("Oops!\n"); } 

macros展开后的if语句是if(i >= 60 * 60 * 1000 / 1 * 1000 - 1)

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

什么types是60 * 60 * 1000 / 1 * 1000 - 1int

int的所有运算符都返回int 。 所以是的, 60 * 60 * 1000 / 1 * 1000 - 1是一个int 。 但3599999999的预期结果对于int来说太大了,所以expression式实际上是-694967297(假设32位int和2的补码)。

这不会发生在文字INT_MAX ,因为大于INT_MAX整数文字是可以保存完整值的types。

60 * 60 * 1000/1 * 1000 – 1 = 3600000 * 1000 – 1,它溢出inttypes,所以结果可以是任何东西(在你的情况下,它是负的,但不一定)。

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

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

这是我的testing结果:

 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的原因,我觉得溢出的效果。

如果在int为64位时使用编译器,则会发现expression式的结果为false。 如果使用int为32位或16位的编译器,则expression式具有未定义的行为,因为signed int的溢出不必环绕。 也许你的确只是环绕一下,但并不是必须的。

3600000000是在编译时可见的常量,所以如果int只有32位,那么编译器将不得不selectlong long(或long long,如果long是64位)。 所以你的其他expression式用足够的位来评估,以避免溢出,结果是正确的。

可能是因为你满足了2147米左右的整数大小,这意味着如果你越过这个表示就变成了负数。 正如其他答案所指出的那样,分割在扩展的时候什么也不做,所以用括号括起macros定义

你很有可能超出有效范围的值为一个有符号整数 – 3600000000是一个相当大的数字!

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

这将导致你的陈述是真实的。

该expression式的每个参数都是一个整数,所以结果将是一个整数。

我想你对macros如何工作感到困惑。 您不使用这些macros的值,而是使用方程本身。 我认为这是你的困惑所在。 我认为你应该在你的macros中使用括号或不使用macros。

我还没有看到任何人提到的是,即使将macros定义完全加上括号也不能完全解决问题。

这个问题有:

 #define BIG_INTERVAL 60 * 60 * 1000 

(提问者承认缺less括号是一个问题)。 但即使如此:

 #define BIG_INTERVAL (60 * 60 * 1000) 

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

该语言表示,大的整数常量是一个足够大的types来保存它们的值(例如,根据这些types的范围, 100000可以是inttypes或long inttypes),但是它没有这样的规则expression式,甚至常量expression式。

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

 #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 

(见道格拉斯·亚当斯)。